summaryrefslogtreecommitdiffstats
path: root/plugins-root
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root')
-rw-r--r--plugins-root/Makefile.am3
-rw-r--r--plugins-root/check_dhcp.c1021
-rw-r--r--plugins-root/check_dhcp.d/config.h50
-rw-r--r--plugins-root/check_icmp.c294
-rw-r--r--plugins-root/check_icmp.d/check_icmp_helpers.c8
-rw-r--r--plugins-root/check_icmp.d/config.h12
-rw-r--r--plugins-root/pst3.c441
-rw-r--r--plugins-root/t/check_dhcp.t24
8 files changed, 1038 insertions, 815 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..9a96547f 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
@@ -122,17 +127,17 @@ static long mac_addr_dlpi(const char *, int, u_char *);
122#define MAX_DHCP_OPTIONS_LENGTH 312 127#define MAX_DHCP_OPTIONS_LENGTH 312
123 128
124typedef struct dhcp_packet_struct { 129typedef struct dhcp_packet_struct {
125 uint8_t op; /* packet type */ 130 uint8_t op; /* packet type */
126 uint8_t htype; /* type of hardware address for this machine (Ethernet, etc) */ 131 uint8_t htype; /* type of hardware address for this machine (Ethernet, etc) */
127 uint8_t hlen; /* length of hardware address (of this machine) */ 132 uint8_t hlen; /* length of hardware address (of this machine) */
128 uint8_t hops; /* hops */ 133 uint8_t hops; /* hops */
129 uint32_t xid; /* random transaction id number - chosen by this machine */ 134 uint32_t xid; /* random transaction id number - chosen by this machine */
130 uint16_t secs; /* seconds used in timing */ 135 uint16_t secs; /* seconds used in timing */
131 uint16_t flags; /* flags */ 136 uint16_t flags; /* flags */
132 struct in_addr ciaddr; /* IP address of this machine (if we already have one) */ 137 struct in_addr ciaddr; /* IP address of this machine (if we already have one) */
133 struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */ 138 struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */
134 struct in_addr siaddr; /* IP address of next server */ 139 struct in_addr siaddr; /* IP address of next server */
135 struct in_addr giaddr; /* IP address of DHCP relay */ 140 struct in_addr giaddr; /* IP address of DHCP relay */
136 unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */ 141 unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */
137 char sname[MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */ 142 char sname[MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */
138 char file[MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */ 143 char file[MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */
@@ -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,69 @@ 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*/,
228static int get_ip_address(int, char *); 203 unsigned char *client_hardware_address);
229 204
230static int send_dhcp_discover(int); 205typedef struct get_ip_address_wrapper {
231static int get_dhcp_offer(int); 206 int error;
232 207 struct in_addr my_ip;
233static int get_results(void); 208} get_ip_address_wrapper;
234 209static get_ip_address_wrapper get_ip_address(int /*sock*/, char * /*interface_name*/);
235static int add_dhcp_offer(struct in_addr, dhcp_packet *); 210
236static int free_dhcp_offer_list(void); 211typedef struct send_dhcp_discover_wrapper {
237static int free_requested_server_list(void); 212 int error;
238 213 uint32_t packet_xid;
239static int create_dhcp_socket(void); 214} send_dhcp_discover_wrapper;
240static int close_dhcp_socket(int); 215static send_dhcp_discover_wrapper
241static int send_dhcp_packet(void *, int, int, struct sockaddr_in *); 216send_dhcp_discover(int socket, bool unicast, struct in_addr dhcp_ip,
242static int receive_dhcp_packet(void *, int, int, int, struct sockaddr_in *); 217 struct in_addr requested_address, bool request_specific_address,
218 struct in_addr my_ip, unsigned char *client_hardware_address);
219typedef struct get_dhcp_offer_wrapper {
220 int error;
221 int valid_responses;
222 dhcp_offer *dhcp_offer_list;
223} get_dhcp_offer_wrapper;
224static get_dhcp_offer_wrapper get_dhcp_offer(int /*sock*/, int dhcpoffer_timeout,
225 uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
226 const unsigned char *client_hardware_address);
227
228static mp_subcheck get_results(bool exclusive, int requested_servers,
229 struct in_addr requested_address, bool request_specific_address,
230 requested_server *requested_server_list, int valid_responses,
231 dhcp_offer *dhcp_offer_list);
232
233typedef struct add_dhcp_offer_wrapper {
234 int error;
235 dhcp_offer *dhcp_offer_list;
236} add_dhcp_offer_wrapper;
237static add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr /*source*/,
238 dhcp_packet * /*offer_packet*/,
239 dhcp_offer *dhcp_offer_list);
240static int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list);
241static int free_requested_server_list(requested_server *requested_server_list);
242
243static int create_dhcp_socket(bool /*unicast*/, char *network_interface_name);
244static int close_dhcp_socket(int /*sock*/);
245static int send_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/,
246 struct sockaddr_in * /*dest*/);
247static int receive_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/,
248 int /*timeout*/, struct sockaddr_in * /*address*/);
243 249
244int main(int argc, char **argv) { 250int main(int argc, char **argv) {
245 int dhcp_socket;
246 int result = STATE_UNKNOWN;
247
248 setlocale(LC_ALL, ""); 251 setlocale(LC_ALL, "");
249 bindtextdomain(PACKAGE, LOCALEDIR); 252 bindtextdomain(PACKAGE, LOCALEDIR);
250 textdomain(PACKAGE); 253 textdomain(PACKAGE);
@@ -252,43 +255,84 @@ int main(int argc, char **argv) {
252 /* Parse extra opts if any */ 255 /* Parse extra opts if any */
253 argv = np_extra_opts(&argc, argv, progname); 256 argv = np_extra_opts(&argc, argv, progname);
254 257
255 if (process_arguments(argc, argv) != OK) { 258 process_arguments_wrapper tmp = process_arguments(argc, argv);
259
260 if (tmp.error != OK) {
256 usage4(_("Could not parse arguments")); 261 usage4(_("Could not parse arguments"));
257 } 262 }
258 263
264 check_dhcp_config config = tmp.config;
265 if (config.output_format_is_set) {
266 mp_set_format(config.output_format);
267 }
268
259 /* create socket for DHCP communications */ 269 /* create socket for DHCP communications */
260 dhcp_socket = create_dhcp_socket(); 270 int dhcp_socket = create_dhcp_socket(config.unicast_mode, config.network_interface_name);
261 271
262 /* get hardware address of client machine */ 272 /* get hardware address of client machine */
263 if (user_specified_mac != NULL) 273 unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
264 memcpy(client_hardware_address, user_specified_mac, 6); 274 if (config.user_specified_mac != NULL) {
265 else 275 memcpy(client_hardware_address, config.user_specified_mac, MAC_ADDR_LEN);
266 get_hardware_address(dhcp_socket, network_interface_name); 276 } else {
277 get_hardware_address(dhcp_socket, config.network_interface_name, client_hardware_address);
278 }
267 279
268 if (unicast) /* get IP address of client machine */ 280 struct in_addr my_ip = {0};
269 get_ip_address(dhcp_socket, network_interface_name); 281
282 if (config.unicast_mode) { /* get IP address of client machine */
283 get_ip_address_wrapper tmp_get_ip =
284 get_ip_address(dhcp_socket, config.network_interface_name);
285 if (tmp_get_ip.error == OK) {
286 my_ip = tmp_get_ip.my_ip;
287 } else {
288 // TODO failed to get own IP
289 die(STATE_UNKNOWN, "Failed to retrieve my own IP address in unicast mode");
290 }
291 }
270 292
271 /* send DHCPDISCOVER packet */ 293 /* send DHCPDISCOVER packet */
272 send_dhcp_discover(dhcp_socket); 294 send_dhcp_discover_wrapper disco_res = send_dhcp_discover(
295 dhcp_socket, config.unicast_mode, config.dhcp_ip, config.requested_address,
296 config.request_specific_address, my_ip, client_hardware_address);
297
298 if (disco_res.error != OK) {
299 // DO something?
300 die(STATE_UNKNOWN, "Failed to send DHCP discover");
301 }
273 302
274 /* wait for a DHCPOFFER packet */ 303 /* wait for a DHCPOFFER packet */
275 get_dhcp_offer(dhcp_socket); 304 get_dhcp_offer_wrapper offer_res = get_dhcp_offer(
305 dhcp_socket, config.dhcpoffer_timeout, disco_res.packet_xid, NULL, client_hardware_address);
306
307 int valid_responses = 0;
308 dhcp_offer *dhcp_offer_list = NULL;
309 if (offer_res.error == OK) {
310 valid_responses = offer_res.valid_responses;
311 dhcp_offer_list = offer_res.dhcp_offer_list;
312 } else {
313 die(STATE_UNKNOWN, "Failed to get DHCP offers");
314 }
276 315
277 /* close socket we created */ 316 /* close socket we created */
278 close_dhcp_socket(dhcp_socket); 317 close_dhcp_socket(dhcp_socket);
279 318
280 /* determine state/plugin output to return */ 319 mp_check overall = mp_check_init();
281 result = get_results();
282 320
321 /* determine state/plugin output to return */
322 mp_subcheck sc_res =
323 get_results(config.exclusive_mode, config.num_of_requested_servers,
324 config.requested_address, config.request_specific_address,
325 config.requested_server_list, valid_responses, dhcp_offer_list);
326 mp_add_subcheck_to_check(&overall, sc_res);
283 /* free allocated memory */ 327 /* free allocated memory */
284 free_dhcp_offer_list(); 328 free_dhcp_offer_list(dhcp_offer_list);
285 free_requested_server_list(); 329 free_requested_server_list(config.requested_server_list);
286 330
287 return result; 331 mp_exit(overall);
288} 332}
289 333
290/* determines hardware address on client machine */ 334/* determines hardware address on client machine */
291static int get_hardware_address(int sock, char *interface_name) { 335int get_hardware_address(int sock, char *interface_name, unsigned char *client_hardware_address) {
292 336
293#if defined(__linux__) 337#if defined(__linux__)
294 struct ifreq ifr; 338 struct ifreq ifr;
@@ -302,7 +346,7 @@ static int get_hardware_address(int sock, char *interface_name) {
302 exit(STATE_UNKNOWN); 346 exit(STATE_UNKNOWN);
303 } 347 }
304 348
305 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, 6); 349 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, MAC_ADDR_LEN);
306 350
307#elif defined(__bsd__) 351#elif defined(__bsd__)
308 /* King 2004 see ACKNOWLEDGEMENTS */ 352 /* King 2004 see ACKNOWLEDGEMENTS */
@@ -326,17 +370,20 @@ static int get_hardware_address(int sock, char *interface_name) {
326 } 370 }
327 371
328 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 372 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
329 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"), interface_name, strerror(errno)); 373 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"),
374 interface_name, strerror(errno));
330 exit(STATE_UNKNOWN); 375 exit(STATE_UNKNOWN);
331 } 376 }
332 377
333 if ((buf = malloc(len)) == NULL) { 378 if ((buf = malloc(len)) == NULL) {
334 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"), interface_name, strerror(errno)); 379 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"),
380 interface_name, strerror(errno));
335 exit(4); 381 exit(4);
336 } 382 }
337 383
338 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 384 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
339 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"), interface_name, strerror(errno)); 385 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"),
386 interface_name, strerror(errno));
340 exit(STATE_UNKNOWN); 387 exit(STATE_UNKNOWN);
341 } 388 }
342 389
@@ -358,20 +405,25 @@ static int get_hardware_address(int sock, char *interface_name) {
358 int i; 405 int i;
359 p = interface_name + strlen(interface_name) - 1; 406 p = interface_name + strlen(interface_name) - 1;
360 for (i = strlen(interface_name) - 1; i > 0; p--) { 407 for (i = strlen(interface_name) - 1; i > 0; p--) {
361 if (isalpha(*p)) 408 if (isalpha(*p)) {
362 break; 409 break;
410 }
363 } 411 }
364 p++; 412 p++;
365 if (p != interface_name) { 413 if (p != interface_name) {
366 unit = atoi(p); 414 unit = atoi(p);
367 strncat(dev, interface_name, 6); 415 strncat(dev, interface_name, 6);
368 } else { 416 } else {
369 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg lnc0.\n"), interface_name); 417 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg "
418 "lnc0.\n"),
419 interface_name);
370 exit(STATE_UNKNOWN); 420 exit(STATE_UNKNOWN);
371 } 421 }
372 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 422 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
373 if (stat != 0) { 423 if (stat != 0) {
374 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 424 printf(
425 _("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"),
426 dev, unit);
375 exit(STATE_UNKNOWN); 427 exit(STATE_UNKNOWN);
376 } 428 }
377 429
@@ -383,7 +435,9 @@ static int get_hardware_address(int sock, char *interface_name) {
383 435
384 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 436 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
385 if (stat != 0) { 437 if (stat != 0) {
386 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 438 printf(
439 _("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"),
440 dev, unit);
387 exit(STATE_UNKNOWN); 441 exit(STATE_UNKNOWN);
388 } 442 }
389 /* Kompf 2000-2003 */ 443 /* Kompf 2000-2003 */
@@ -393,14 +447,15 @@ static int get_hardware_address(int sock, char *interface_name) {
393 exit(STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
394#endif 448#endif
395 449
396 if (verbose) 450 if (verbose) {
397 print_hardware_address(client_hardware_address); 451 print_hardware_address(client_hardware_address);
452 }
398 453
399 return OK; 454 return OK;
400} 455}
401 456
402/* determines IP address of the client interface */ 457/* determines IP address of the client interface */
403static int get_ip_address(int sock, char *interface_name) { 458get_ip_address_wrapper get_ip_address(int sock, char *interface_name) {
404#if defined(SIOCGIFADDR) 459#if defined(SIOCGIFADDR)
405 struct ifreq ifr; 460 struct ifreq ifr;
406 461
@@ -412,28 +467,30 @@ static int get_ip_address(int sock, char *interface_name) {
412 exit(STATE_UNKNOWN); 467 exit(STATE_UNKNOWN);
413 } 468 }
414 469
415 my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
416
417#else 470#else
418 printf(_("Error: Cannot get interface IP address on this platform.\n")); 471 printf(_("Error: Cannot get interface IP address on this platform.\n"));
419 exit(STATE_UNKNOWN); 472 exit(STATE_UNKNOWN);
420#endif 473#endif
421 474
422 if (verbose) 475 get_ip_address_wrapper result = {
423 printf(_("Pretending to be relay client %s\n"), inet_ntoa(my_ip)); 476 .error = OK,
477 .my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,
478 };
424 479
425 return OK; 480 if (verbose) {
481 printf(_("Pretending to be relay client %s\n"), inet_ntoa(result.my_ip));
482 }
483
484 return result;
426} 485}
427 486
428/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 487/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */
429static int send_dhcp_discover(int sock) { 488static send_dhcp_discover_wrapper send_dhcp_discover(int sock, bool unicast, struct in_addr dhcp_ip,
430 dhcp_packet discover_packet; 489 struct in_addr requested_address,
431 struct sockaddr_in sockaddr_broadcast; 490 bool request_specific_address,
432 unsigned short opts; 491 struct in_addr my_ip,
433 492 unsigned char *client_hardware_address) {
434 /* clear the packet data structure */ 493 dhcp_packet discover_packet = {0};
435 bzero(&discover_packet, sizeof(discover_packet));
436
437 /* boot request flag (backward compatible with BOOTP servers) */ 494 /* boot request flag (backward compatible with BOOTP servers) */
438 discover_packet.op = BOOTREQUEST; 495 discover_packet.op = BOOTREQUEST;
439 496
@@ -443,12 +500,15 @@ static int send_dhcp_discover(int sock) {
443 /* length of our hardware address */ 500 /* length of our hardware address */
444 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH; 501 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;
445 502
503 send_dhcp_discover_wrapper result = {
504 .error = OK,
505 };
446 /* 506 /*
447 * transaction ID is supposed to be random. 507 * transaction ID is supposed to be random.
448 */ 508 */
449 srand(time(NULL) ^ getpid()); 509 srand(time(NULL) ^ getpid());
450 packet_xid = random(); 510 result.packet_xid = random();
451 discover_packet.xid = htonl(packet_xid); 511 discover_packet.xid = htonl(result.packet_xid);
452 512
453 /*discover_packet.secs=htons(65535);*/ 513 /*discover_packet.secs=htons(65535);*/
454 discover_packet.secs = 0xFF; 514 discover_packet.secs = 0xFF;
@@ -468,10 +528,11 @@ static int send_dhcp_discover(int sock) {
468 discover_packet.options[2] = '\x53'; 528 discover_packet.options[2] = '\x53';
469 discover_packet.options[3] = '\x63'; 529 discover_packet.options[3] = '\x63';
470 530
471 opts = 4; 531 unsigned short opts = 4;
472 /* DHCP message type is embedded in options field */ 532 /* DHCP message type is embedded in options field */
473 discover_packet.options[opts++] = DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ 533 discover_packet.options[opts++] =
474 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */ 534 DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */
535 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */
475 discover_packet.options[opts++] = DHCPDISCOVER; 536 discover_packet.options[opts++] = DHCPDISCOVER;
476 537
477 /* the IP address we're requesting */ 538 /* the IP address we're requesting */
@@ -484,21 +545,25 @@ static int send_dhcp_discover(int sock) {
484 discover_packet.options[opts++] = (char)DHCP_OPTION_END; 545 discover_packet.options[opts++] = (char)DHCP_OPTION_END;
485 546
486 /* unicast fields */ 547 /* unicast fields */
487 if (unicast) 548 if (unicast) {
488 discover_packet.giaddr.s_addr = my_ip.s_addr; 549 discover_packet.giaddr.s_addr = my_ip.s_addr;
550 }
489 551
490 /* see RFC 1542, 4.1.1 */ 552 /* see RFC 1542, 4.1.1 */
491 discover_packet.hops = unicast ? 1 : 0; 553 discover_packet.hops = unicast ? 1 : 0;
492 554
493 /* send the DHCPDISCOVER packet to broadcast address */ 555 /* send the DHCPDISCOVER packet to broadcast address */
494 sockaddr_broadcast.sin_family = AF_INET; 556 struct sockaddr_in sockaddr_broadcast = {
495 sockaddr_broadcast.sin_port = htons(DHCP_SERVER_PORT); 557 .sin_family = AF_INET,
496 sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST; 558 .sin_port = htons(DHCP_SERVER_PORT),
497 bzero(&sockaddr_broadcast.sin_zero, sizeof(sockaddr_broadcast.sin_zero)); 559 .sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST,
560 };
498 561
499 if (verbose) { 562 if (verbose) {
500 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr), ntohs(sockaddr_broadcast.sin_port)); 563 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr),
501 printf("DHCPDISCOVER XID: %u (0x%X)\n", ntohl(discover_packet.xid), ntohl(discover_packet.xid)); 564 ntohs(sockaddr_broadcast.sin_port));
565 printf("DHCPDISCOVER XID: %u (0x%X)\n", ntohl(discover_packet.xid),
566 ntohl(discover_packet.xid));
502 printf("DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr)); 567 printf("DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr));
503 printf("DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr)); 568 printf("DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr));
504 printf("DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr)); 569 printf("DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr));
@@ -508,56 +573,58 @@ static int send_dhcp_discover(int sock) {
508 /* send the DHCPDISCOVER packet out */ 573 /* send the DHCPDISCOVER packet out */
509 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast); 574 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast);
510 575
511 if (verbose) 576 if (verbose) {
512 printf("\n\n"); 577 printf("\n\n");
578 }
513 579
514 return OK; 580 return result;
515} 581}
516 582
517/* waits for a DHCPOFFER message from one or more DHCP servers */ 583/* waits for a DHCPOFFER message from one or more DHCP servers */
518static int get_dhcp_offer(int sock) { 584get_dhcp_offer_wrapper get_dhcp_offer(int sock, int dhcpoffer_timeout, uint32_t packet_xid,
519 dhcp_packet offer_packet; 585 dhcp_offer *dhcp_offer_list,
520 struct sockaddr_in source; 586 const unsigned char *client_hardware_address) {
521 struct sockaddr_in via;
522 int result = OK;
523 int responses = 0;
524 int x;
525 time_t start_time; 587 time_t start_time;
526 time_t current_time;
527
528 time(&start_time); 588 time(&start_time);
529 589
590 int result = OK;
591 int responses = 0;
592 int valid_responses = 0;
530 /* receive as many responses as we can */ 593 /* receive as many responses as we can */
531 for (responses = 0, valid_responses = 0;;) { 594 for (;;) {
532 595 time_t current_time;
533 time(&current_time); 596 time(&current_time);
534 if ((current_time - start_time) >= dhcpoffer_timeout) 597 if ((current_time - start_time) >= dhcpoffer_timeout) {
535 break; 598 break;
599 }
536 600
537 if (verbose) 601 if (verbose) {
538 printf("\n\n"); 602 printf("\n\n");
603 }
539 604
540 bzero(&source, sizeof(source)); 605 struct sockaddr_in source = {0};
541 bzero(&via, sizeof(via)); 606 dhcp_packet offer_packet = {0};
542 bzero(&offer_packet, sizeof(offer_packet));
543 607
544 result = OK; 608 result = OK;
545 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout, &source); 609 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout,
610 &source);
546 611
547 if (result != OK) { 612 if (result != OK) {
548 if (verbose) 613 if (verbose) {
549 printf(_("Result=ERROR\n")); 614 printf(_("Result=ERROR\n"));
615 }
550 616
551 continue; 617 continue;
552 } else { 618 }
553 if (verbose) 619 if (verbose) {
554 printf(_("Result=OK\n")); 620 printf(_("Result=OK\n"));
555
556 responses++;
557 } 621 }
558 622
623 responses++;
624
559 /* The "source" is either a server or a relay. */ 625 /* The "source" is either a server or a relay. */
560 /* Save a copy of "source" into "via" even if it's via itself */ 626 /* Save a copy of "source" into "via" even if it's via itself */
627 struct sockaddr_in via = {0};
561 memcpy(&via, &source, sizeof(source)); 628 memcpy(&via, &source, sizeof(source));
562 629
563 if (verbose) { 630 if (verbose) {
@@ -568,30 +635,38 @@ static int get_dhcp_offer(int sock) {
568 635
569 /* check packet xid to see if its the same as the one we used in the discover packet */ 636 /* 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) { 637 if (ntohl(offer_packet.xid) != packet_xid) {
571 if (verbose) 638 if (verbose) {
572 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"), ntohl(offer_packet.xid), packet_xid); 639 printf(
640 _("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"),
641 ntohl(offer_packet.xid), packet_xid);
642 }
573 643
574 continue; 644 continue;
575 } 645 }
576 646
577 /* check hardware address */ 647 /* check hardware address */
578 result = OK; 648 result = OK;
579 if (verbose) 649 if (verbose) {
580 printf("DHCPOFFER chaddr: "); 650 printf("DHCPOFFER chaddr: ");
651 }
581 652
582 for (x = 0; x < ETHERNET_HARDWARE_ADDRESS_LENGTH; x++) { 653 for (int i = 0; i < ETHERNET_HARDWARE_ADDRESS_LENGTH; i++) {
583 if (verbose) 654 if (verbose) {
584 printf("%02X", (unsigned char)offer_packet.chaddr[x]); 655 printf("%02X", offer_packet.chaddr[i]);
656 }
585 657
586 if (offer_packet.chaddr[x] != client_hardware_address[x]) 658 if (offer_packet.chaddr[i] != client_hardware_address[i]) {
587 result = ERROR; 659 result = ERROR;
660 }
588 } 661 }
589 if (verbose) 662 if (verbose) {
590 printf("\n"); 663 printf("\n");
664 }
591 665
592 if (result == ERROR) { 666 if (result == ERROR) {
593 if (verbose) 667 if (verbose) {
594 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n")); 668 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n"));
669 }
595 670
596 continue; 671 continue;
597 } 672 }
@@ -603,7 +678,13 @@ static int get_dhcp_offer(int sock) {
603 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr)); 678 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr));
604 } 679 }
605 680
606 add_dhcp_offer(source.sin_addr, &offer_packet); 681 add_dhcp_offer_wrapper add_res =
682 add_dhcp_offer(source.sin_addr, &offer_packet, dhcp_offer_list);
683 if (add_res.error != OK) {
684 // TODO
685 } else {
686 dhcp_offer_list = add_res.dhcp_offer_list;
687 }
607 688
608 valid_responses++; 689 valid_responses++;
609 } 690 }
@@ -613,104 +694,104 @@ static int get_dhcp_offer(int sock) {
613 printf(_("Valid responses for this machine: %d\n"), valid_responses); 694 printf(_("Valid responses for this machine: %d\n"), valid_responses);
614 } 695 }
615 696
616 return OK; 697 get_dhcp_offer_wrapper ret_val = {
698 .error = OK,
699 .valid_responses = valid_responses,
700 .dhcp_offer_list = dhcp_offer_list,
701 };
702 return ret_val;
617} 703}
618 704
619/* sends a DHCP packet */ 705/* sends a DHCP packet */
620static int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) { 706int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) {
621 int result; 707 int result =
622 708 sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
623 result = sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
624 709
625 if (verbose) 710 if (verbose) {
626 printf(_("send_dhcp_packet result: %d\n"), result); 711 printf(_("send_dhcp_packet result: %d\n"), result);
712 }
627 713
628 if (result < 0) 714 if (result < 0) {
629 return ERROR; 715 return ERROR;
716 }
630 717
631 return OK; 718 return OK;
632} 719}
633 720
634/* receives a DHCP packet */ 721/* receives a DHCP packet */
635static int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address) { 722int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout,
636 struct timeval tv; 723 struct sockaddr_in *address) {
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) */ 724 /* wait for data to arrive (up time timeout) */
645 tv.tv_sec = timeout; 725 struct timeval timeout_val = {
646 tv.tv_usec = 0; 726 .tv_sec = timeout,
727 .tv_usec = 0,
728 };
729 fd_set readfds;
647 FD_ZERO(&readfds); 730 FD_ZERO(&readfds);
731 fd_set oobfds;
648 FD_ZERO(&oobfds); 732 FD_ZERO(&oobfds);
649 FD_SET(sock, &readfds); 733 FD_SET(sock, &readfds);
650 FD_SET(sock, &oobfds); 734 FD_SET(sock, &oobfds);
651 nfound = select(sock + 1, &readfds, NULL, &oobfds, &tv); 735 int nfound = select(sock + 1, &readfds, NULL, &oobfds, &timeout_val);
652 736
653 /* make sure some data has arrived */ 737 /* make sure some data has arrived */
654 if (!FD_ISSET(sock, &readfds)) { 738 if (!FD_ISSET(sock, &readfds)) {
655 if (verbose) 739 if (verbose) {
656 printf(_("No (more) data received (nfound: %d)\n"), nfound); 740 printf(_("No (more) data received (nfound: %d)\n"), nfound);
741 }
657 return ERROR; 742 return ERROR;
658 } 743 }
659 744
660 else { 745 struct sockaddr_in source_address = {0};
661 bzero(&source_address, sizeof(source_address)); 746 socklen_t address_size = sizeof(source_address);
662 address_size = sizeof(source_address); 747 int recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0,
663 recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)&source_address, &address_size); 748 (struct sockaddr *)&source_address, &address_size);
664 if (verbose) 749 if (verbose) {
665 printf("recv_result: %d\n", recv_result); 750 printf("recv_result: %d\n", recv_result);
666 751 }
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 752
679 memcpy(address, &source_address, sizeof(source_address)); 753 if (recv_result == -1) {
680 return OK; 754 if (verbose) {
755 printf(_("recvfrom() failed, "));
756 printf("errno: (%d) -> %s\n", errno, strerror(errno));
681 } 757 }
758 return ERROR;
759 }
760 if (verbose) {
761 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
762 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
682 } 763 }
683 764
765 memcpy(address, &source_address, sizeof(source_address));
684 return OK; 766 return OK;
685} 767}
686 768
687/* creates a socket for DHCP communication */ 769/* creates a socket for DHCP communication */
688static int create_dhcp_socket(void) { 770int 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. */ 771 /* 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 */ 772 /* listen to DHCP server port if we're in unicast mode */
698 myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT); 773 struct sockaddr_in myname = {
699 myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY; 774 .sin_family = AF_INET,
700 bzero(&myname.sin_zero, sizeof(myname.sin_zero)); 775 .sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT),
776 // TODO previously the next line was trying to use our own IP, we was not set
777 // until some point later, so it was removed. Recheck whether it is actually
778 // necessary/useful
779 .sin_addr.s_addr = INADDR_ANY,
780 };
701 781
702 /* create a socket for DHCP communications */ 782 /* create a socket for DHCP communications */
703 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 783 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
704 if (sock < 0) { 784 if (sock < 0) {
705 printf(_("Error: Could not create socket!\n")); 785 printf(_("Error: Could not create socket!\n"));
706 exit(STATE_UNKNOWN); 786 exit(STATE_UNKNOWN);
707 } 787 }
708 788
709 if (verbose) 789 if (verbose) {
710 printf("DHCP socket: %d\n", sock); 790 printf("DHCP socket: %d\n", sock);
791 }
711 792
712 /* set the reuse address flag so we don't get errors when restarting */ 793 /* set the reuse address flag so we don't get errors when restarting */
713 flag = 1; 794 int flag = 1;
714 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) { 795 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")); 796 printf(_("Error: Could not set reuse address option on DHCP socket!\n"));
716 exit(STATE_UNKNOWN); 797 exit(STATE_UNKNOWN);
@@ -722,12 +803,14 @@ static int create_dhcp_socket(void) {
722 exit(STATE_UNKNOWN); 803 exit(STATE_UNKNOWN);
723 } 804 }
724 805
806 struct ifreq interface;
725 /* bind socket to interface */ 807 /* bind socket to interface */
726#if defined(__linux__) 808#if defined(__linux__)
727 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1); 809 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1);
728 interface.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0'; 810 interface.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0';
729 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) { 811 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) {
730 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"), network_interface_name); 812 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"),
813 network_interface_name);
731 exit(STATE_UNKNOWN); 814 exit(STATE_UNKNOWN);
732 } 815 }
733 816
@@ -738,7 +821,8 @@ static int create_dhcp_socket(void) {
738 821
739 /* bind the socket */ 822 /* bind the socket */
740 if (bind(sock, (struct sockaddr *)&myname, sizeof(myname)) < 0) { 823 if (bind(sock, (struct sockaddr *)&myname, sizeof(myname)) < 0) {
741 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"), DHCP_CLIENT_PORT); 824 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"),
825 DHCP_CLIENT_PORT);
742 exit(STATE_UNKNOWN); 826 exit(STATE_UNKNOWN);
743 } 827 }
744 828
@@ -746,105 +830,121 @@ static int create_dhcp_socket(void) {
746} 830}
747 831
748/* closes DHCP socket */ 832/* closes DHCP socket */
749static int close_dhcp_socket(int sock) { 833int close_dhcp_socket(int sock) {
750
751 close(sock); 834 close(sock);
752
753 return OK; 835 return OK;
754} 836}
755 837
756/* adds a requested server address to list in memory */ 838/* adds a requested server address to list in memory */
757static int add_requested_server(struct in_addr server_address) { 839int add_requested_server(struct in_addr server_address, int *requested_servers,
758 requested_server *new_server; 840 requested_server **requested_server_list) {
759 841 requested_server *new_server = (requested_server *)malloc(sizeof(requested_server));
760 new_server = (requested_server *)malloc(sizeof(requested_server)); 842 if (new_server == NULL) {
761 if (new_server == NULL)
762 return ERROR; 843 return ERROR;
844 }
763 845
764 new_server->server_address = server_address; 846 new_server->server_address = server_address;
765 new_server->answered = false; 847 new_server->answered = false;
766 848
767 new_server->next = requested_server_list; 849 new_server->next = *requested_server_list;
768 requested_server_list = new_server; 850 *requested_server_list = new_server;
769 851
770 requested_servers++; 852 *requested_servers += 1;
771 853
772 if (verbose) 854 if (verbose) {
773 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address)); 855 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address));
856 }
774 857
775 return OK; 858 return OK;
776} 859}
777 860
778/* adds a DHCP OFFER to list in memory */ 861/* adds a DHCP OFFER to list in memory */
779static int add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet) { 862add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet,
863 dhcp_offer *dhcp_offer_list) {
864 if (offer_packet == NULL) {
865 add_dhcp_offer_wrapper tmp = {
866 .error = ERROR,
867 };
868 return tmp;
869 }
870
871 uint32_t dhcp_lease_time = 0;
872 uint32_t dhcp_renewal_time = 0;
873 uint32_t dhcp_rebinding_time = 0;
780 dhcp_offer *new_offer; 874 dhcp_offer *new_offer;
781 int x;
782 unsigned option_type;
783 unsigned option_length;
784 struct in_addr serv_ident = {0}; 875 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 */ 876 /* process all DHCP options present in the packet */
790 for (x = 4; x < MAX_DHCP_OPTIONS_LENGTH - 1;) { 877 for (int dchp_opt_idx = 4; dchp_opt_idx < MAX_DHCP_OPTIONS_LENGTH - 1;) {
791 878
792 if ((int)offer_packet->options[x] == -1) 879 if ((int)offer_packet->options[dchp_opt_idx] == -1) {
793 break; 880 break;
881 }
794 882
795 /* get option type */ 883 /* get option type */
796 option_type = offer_packet->options[x++]; 884 unsigned option_type = offer_packet->options[dchp_opt_idx++];
797 885
798 /* get option length */ 886 /* get option length */
799 option_length = offer_packet->options[x++]; 887 unsigned option_length = offer_packet->options[dchp_opt_idx++];
800 888
801 if (verbose) 889 if (verbose) {
802 printf("Option: %d (0x%02X)\n", option_type, option_length); 890 printf("Option: %d (0x%02X)\n", option_type, option_length);
891 }
803 892
804 /* get option data */ 893 /* get option data */
805 switch (option_type) { 894 switch (option_type) {
806 case DHCP_OPTION_LEASE_TIME: 895 case DHCP_OPTION_LEASE_TIME:
807 memcpy(&dhcp_lease_time, &offer_packet->options[x], sizeof(dhcp_lease_time)); 896 memcpy(&dhcp_lease_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_lease_time));
808 dhcp_lease_time = ntohl(dhcp_lease_time); 897 dhcp_lease_time = ntohl(dhcp_lease_time);
809 break; 898 break;
810 case DHCP_OPTION_RENEWAL_TIME: 899 case DHCP_OPTION_RENEWAL_TIME:
811 memcpy(&dhcp_renewal_time, &offer_packet->options[x], sizeof(dhcp_renewal_time)); 900 memcpy(&dhcp_renewal_time, &offer_packet->options[dchp_opt_idx],
901 sizeof(dhcp_renewal_time));
812 dhcp_renewal_time = ntohl(dhcp_renewal_time); 902 dhcp_renewal_time = ntohl(dhcp_renewal_time);
813 break; 903 break;
814 case DHCP_OPTION_REBINDING_TIME: 904 case DHCP_OPTION_REBINDING_TIME:
815 memcpy(&dhcp_rebinding_time, &offer_packet->options[x], sizeof(dhcp_rebinding_time)); 905 memcpy(&dhcp_rebinding_time, &offer_packet->options[dchp_opt_idx],
906 sizeof(dhcp_rebinding_time));
816 dhcp_rebinding_time = ntohl(dhcp_rebinding_time); 907 dhcp_rebinding_time = ntohl(dhcp_rebinding_time);
817 break; 908 break;
818 case DHCP_OPTION_SERVER_IDENTIFIER: 909 case DHCP_OPTION_SERVER_IDENTIFIER:
819 memcpy(&serv_ident.s_addr, &offer_packet->options[x], sizeof(serv_ident.s_addr)); 910 memcpy(&serv_ident.s_addr, &offer_packet->options[dchp_opt_idx],
911 sizeof(serv_ident.s_addr));
820 break; 912 break;
821 } 913 }
822 914
823 /* skip option data we're ignoring */ 915 /* skip option data we're ignoring */
824 if (option_type == 0) /* "pad" option, see RFC 2132 (3.1) */ 916 if (option_type == 0) { /* "pad" option, see RFC 2132 (3.1) */
825 x += 1; 917 dchp_opt_idx += 1;
826 else 918 } else {
827 x += option_length; 919 dchp_opt_idx += option_length;
920 }
828 } 921 }
829 922
830 if (verbose) { 923 if (verbose) {
831 if (dhcp_lease_time == DHCP_INFINITE_TIME) 924 if (dhcp_lease_time == DHCP_INFINITE_TIME) {
832 printf(_("Lease Time: Infinite\n")); 925 printf(_("Lease Time: Infinite\n"));
833 else 926 } else {
834 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time); 927 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time);
835 if (dhcp_renewal_time == DHCP_INFINITE_TIME) 928 }
929 if (dhcp_renewal_time == DHCP_INFINITE_TIME) {
836 printf(_("Renewal Time: Infinite\n")); 930 printf(_("Renewal Time: Infinite\n"));
837 else 931 } else {
838 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time); 932 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time);
839 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) 933 }
934 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) {
840 printf(_("Rebinding Time: Infinite\n")); 935 printf(_("Rebinding Time: Infinite\n"));
936 }
841 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time); 937 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time);
842 } 938 }
843 939
844 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer)); 940 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer));
845 941
846 if (new_offer == NULL) 942 if (new_offer == NULL) {
847 return ERROR; 943 add_dhcp_offer_wrapper tmp = {
944 .error = ERROR,
945 };
946 return tmp;
947 }
848 948
849 /* 949 /*
850 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the 950 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the
@@ -874,15 +974,18 @@ static int add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet) {
874 new_offer->next = dhcp_offer_list; 974 new_offer->next = dhcp_offer_list;
875 dhcp_offer_list = new_offer; 975 dhcp_offer_list = new_offer;
876 976
877 return OK; 977 add_dhcp_offer_wrapper result = {
978 .error = OK,
979 .dhcp_offer_list = dhcp_offer_list,
980 };
981
982 return result;
878} 983}
879 984
880/* frees memory allocated to DHCP OFFER list */ 985/* frees memory allocated to DHCP OFFER list */
881static int free_dhcp_offer_list(void) { 986int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list) {
882 dhcp_offer *this_offer;
883 dhcp_offer *next_offer; 987 dhcp_offer *next_offer;
884 988 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; 989 next_offer = this_offer->next;
887 free(this_offer); 990 free(this_offer);
888 } 991 }
@@ -891,11 +994,10 @@ static int free_dhcp_offer_list(void) {
891} 994}
892 995
893/* frees memory allocated to requested server list */ 996/* frees memory allocated to requested server list */
894static int free_requested_server_list(void) { 997int free_requested_server_list(requested_server *requested_server_list) {
895 requested_server *this_server;
896 requested_server *next_server; 998 requested_server *next_server;
897 999 for (requested_server *this_server = requested_server_list; this_server != NULL;
898 for (this_server = requested_server_list; this_server != NULL; this_server = next_server) { 1000 this_server = next_server) {
899 next_server = this_server->next; 1001 next_server = this_server->next;
900 free(this_server); 1002 free(this_server);
901 } 1003 }
@@ -904,39 +1006,68 @@ static int free_requested_server_list(void) {
904} 1006}
905 1007
906/* gets state and plugin output to return */ 1008/* gets state and plugin output to return */
907static int get_results(void) { 1009mp_subcheck get_results(bool exclusive, const int requested_servers,
908 dhcp_offer *temp_offer, *undesired_offer = NULL; 1010 const struct in_addr requested_address, bool request_specific_address,
909 requested_server *temp_server; 1011 requested_server *requested_server_list, int valid_responses,
910 int result; 1012 dhcp_offer *dhcp_offer_list) {
911 uint32_t max_lease_time = 0; 1013 mp_subcheck sc_dhcp_results = mp_subcheck_init();
1014 sc_dhcp_results = mp_set_subcheck_default_state(sc_dhcp_results, STATE_OK);
912 1015
913 received_requested_address = false; 1016 /* we didn't receive any DHCPOFFERs */
914 1017 if (dhcp_offer_list == NULL) {
915 /* checks responses from requested servers */ 1018 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
916 requested_responses = 0; 1019 xasprintf(&sc_dhcp_results.output, "%s", "No DHCPOFFERs were received");
917 if (requested_servers > 0) { 1020 return sc_dhcp_results;
1021 }
918 1022
919 for (temp_server = requested_server_list; temp_server != NULL; temp_server = temp_server->next) { 1023 if (valid_responses == 0) {
1024 // No valid responses at all, so early exit here
1025 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
1026 xasprintf(&sc_dhcp_results.output, "No valid responses received");
1027 return sc_dhcp_results;
1028 }
920 1029
921 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1030 if (valid_responses == 1) {
1031 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFER", valid_responses);
1032 } else {
1033 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFERs", valid_responses);
1034 }
922 1035
1036 bool received_requested_address = false;
1037 dhcp_offer *undesired_offer = NULL;
1038 uint32_t max_lease_time = 0;
1039 /* checks responses from requested servers */
1040 int requested_responses = 0;
1041 if (requested_servers > 0) {
1042 for (requested_server *temp_server = requested_server_list; temp_server != NULL;
1043 temp_server = temp_server->next) {
1044 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1045 temp_offer = temp_offer->next) {
923 /* get max lease time we were offered */ 1046 /* get max lease time we were offered */
924 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 1047 if (temp_offer->lease_time > max_lease_time ||
1048 temp_offer->lease_time == DHCP_INFINITE_TIME) {
925 max_lease_time = temp_offer->lease_time; 1049 max_lease_time = temp_offer->lease_time;
1050 }
926 1051
927 /* see if we got the address we requested */ 1052 /* see if we got the address we requested */
928 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 1053 if (!memcmp(&requested_address, &temp_offer->offered_address,
1054 sizeof(requested_address))) {
929 received_requested_address = true; 1055 received_requested_address = true;
1056 }
930 1057
931 /* see if the servers we wanted a response from talked to us or not */ 1058 /* 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))) { 1059 if (!memcmp(&temp_offer->server_address, &temp_server->server_address,
1060 sizeof(temp_server->server_address))) {
933 if (verbose) { 1061 if (verbose) {
934 printf(_("DHCP Server Match: Offerer=%s"), inet_ntoa(temp_offer->server_address)); 1062 printf(_("DHCP Server Match: Offerer=%s"),
1063 inet_ntoa(temp_offer->server_address));
935 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address)); 1064 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address));
936 if (temp_server->answered) 1065 if (temp_server->answered) {
937 printf(_(" (duplicate)")); 1066 printf(_(" (duplicate)"));
1067 }
938 printf(_("\n")); 1068 printf(_("\n"));
939 } 1069 }
1070
940 if (!temp_server->answered) { 1071 if (!temp_server->answered) {
941 requested_responses++; 1072 requested_responses++;
942 temp_server->answered = true; 1073 temp_server->answered = true;
@@ -947,160 +1078,188 @@ static int get_results(void) {
947 } 1078 }
948 1079
949 /* exclusive mode: check for undesired offers */ 1080 /* exclusive mode: check for undesired offers */
950 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1081 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1082 temp_offer = temp_offer->next) {
951 if (!temp_offer->desired) { 1083 if (!temp_offer->desired) {
952 undesired_offer = temp_offer; /* Checks only for the first undesired offer */ 1084 undesired_offer = temp_offer; /* Checks only for the first undesired offer */
953 break; /* no further checks needed */ 1085 break; /* no further checks needed */
954 } 1086 }
955 } 1087 }
956 }
957 1088
958 /* else check and see if we got our requested address from any server */ 1089 mp_subcheck sc_rqust_srvs = mp_subcheck_init();
959 else { 1090 xasprintf(&sc_rqust_srvs.output, "%d of %d requested servers responded",
1091 requested_responses, requested_servers);
960 1092
961 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1093 if (requested_responses == requested_servers) {
1094 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_OK);
1095 } else if (requested_responses == 0) {
1096 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_CRITICAL);
1097 } else if (requested_responses < requested_servers) {
1098 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1099 } else {
1100 // We received more(!) responses than we asked for?
1101 // This case shouldn't happen, but is here for completion
1102 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1103 }
1104 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqust_srvs);
962 1105
1106 } else {
1107 /* else check and see if we got our requested address from any server */
1108 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1109 temp_offer = temp_offer->next) {
963 /* get max lease time we were offered */ 1110 /* get max lease time we were offered */
964 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 1111 if (temp_offer->lease_time > max_lease_time ||
1112 temp_offer->lease_time == DHCP_INFINITE_TIME) {
965 max_lease_time = temp_offer->lease_time; 1113 max_lease_time = temp_offer->lease_time;
1114 }
966 1115
967 /* see if we got the address we requested */ 1116 /* see if we got the address we requested */
968 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 1117 if (!memcmp(&requested_address, &temp_offer->offered_address,
1118 sizeof(requested_address))) {
969 received_requested_address = true; 1119 received_requested_address = true;
1120 }
970 } 1121 }
971 } 1122 }
972 1123
973 result = STATE_OK; 1124 if (max_lease_time == DHCP_INFINITE_TIME) {
974 if (valid_responses == 0) 1125 xasprintf(&sc_dhcp_results.output, "%s, max lease time = Infinity", sc_dhcp_results.output);
975 result = STATE_CRITICAL; 1126 } else {
976 else if (requested_servers > 0 && requested_responses == 0) 1127 xasprintf(&sc_dhcp_results.output, "%s, max lease time = %" PRIu32 " seconds",
977 result = STATE_CRITICAL; 1128 sc_dhcp_results.output, max_lease_time);
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 } 1129 }
1000 1130
1001 printf(_("Received %d DHCPOFFER(s)"), valid_responses); 1131 if (exclusive) {
1132 mp_subcheck sc_rogue_server = mp_subcheck_init();
1002 1133
1003 if (exclusive && undesired_offer) { 1134 if (undesired_offer != NULL) {
1004 printf(_(", Rogue DHCP Server detected! Server %s"), inet_ntoa(undesired_offer->server_address)); 1135 // We wanted to get a DHCPOFFER exclusively from one machine, but another one
1005 printf(_(" offered %s \n"), inet_ntoa(undesired_offer->offered_address)); 1136 // sent one (too)
1006 return result; 1137 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_CRITICAL);
1007 }
1008 1138
1009 if (requested_servers > 0) 1139 // Get the addresses for printout
1010 printf(_(", %s%d of %d requested servers responded"), ((requested_responses < requested_servers) && requested_responses > 0) ? "only " : "", requested_responses, 1140 // 1.address of the sending server
1011 requested_servers); 1141 char server_address[INET_ADDRSTRLEN];
1142 const char *server_address_transformed = inet_ntop(
1143 AF_INET, &undesired_offer->server_address, server_address, sizeof(server_address));
1012 1144
1013 if (request_specific_address) 1145 if (server_address != server_address_transformed) {
1014 printf(_(", requested address (%s) was %soffered"), inet_ntoa(requested_address), (received_requested_address) ? "" : _("not ")); 1146 die(STATE_UNKNOWN, "inet_ntop failed");
1147 }
1015 1148
1016 printf(_(", max lease time = ")); 1149 // 2.address offered
1017 if (max_lease_time == DHCP_INFINITE_TIME) 1150 char offered_address[INET_ADDRSTRLEN];
1018 printf(_("Infinity")); 1151 const char *offered_address_transformed =
1019 else 1152 inet_ntop(AF_INET, &undesired_offer->offered_address, offered_address,
1020 printf("%lu sec", (unsigned long)max_lease_time); 1153 sizeof(offered_address));
1021 1154
1022 printf(".\n"); 1155 if (offered_address != offered_address_transformed) {
1156 die(STATE_UNKNOWN, "inet_ntop failed");
1157 }
1023 1158
1024 return result; 1159 xasprintf(&sc_rogue_server.output, "Rogue DHCP Server detected! Server %s offered %s",
1160 server_address, offered_address);
1161 } else {
1162 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_OK);
1163 xasprintf(&sc_rogue_server.output, "No Rogue DHCP Server detected");
1164 }
1165 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rogue_server);
1166 }
1167
1168 if (request_specific_address) {
1169 mp_subcheck sc_rqustd_addr = mp_subcheck_init();
1170
1171 if (received_requested_address) {
1172 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_OK);
1173 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was offered",
1174 inet_ntoa(requested_address));
1175 } else {
1176 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_WARNING);
1177 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was NOT offered",
1178 inet_ntoa(requested_address));
1179 }
1180
1181 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqustd_addr);
1182 }
1183
1184 return sc_dhcp_results;
1025} 1185}
1026 1186
1027/* process command-line arguments */ 1187/* process command-line arguments */
1028static int process_arguments(int argc, char **argv) { 1188process_arguments_wrapper process_arguments(int argc, char **argv) {
1029 if (argc < 1) 1189 if (argc < 1) {
1030 return ERROR; 1190 process_arguments_wrapper tmp = {
1191 .error = ERROR,
1192 };
1193 return tmp;
1194 }
1031 1195
1032 call_getopt(argc, argv); 1196 enum {
1033 return validate_arguments(argc); 1197 output_format_index = CHAR_MAX + 1,
1034} 1198 };
1035 1199
1036static int call_getopt(int argc, char **argv) {
1037 extern int optind;
1038 int option_index = 0; 1200 int option_index = 0;
1039 static struct option long_options[] = {{"serverip", required_argument, 0, 's'}, 1201 static struct option long_options[] = {
1040 {"requestedip", required_argument, 0, 'r'}, 1202 {"serverip", required_argument, 0, 's'},
1041 {"timeout", required_argument, 0, 't'}, 1203 {"requestedip", required_argument, 0, 'r'},
1042 {"interface", required_argument, 0, 'i'}, 1204 {"timeout", required_argument, 0, 't'},
1043 {"mac", required_argument, 0, 'm'}, 1205 {"interface", required_argument, 0, 'i'},
1044 {"unicast", no_argument, 0, 'u'}, 1206 {"mac", required_argument, 0, 'm'},
1045 {"exclusive", no_argument, 0, 'x'}, 1207 {"unicast", no_argument, 0, 'u'},
1046 {"verbose", no_argument, 0, 'v'}, 1208 {"exclusive", no_argument, 0, 'x'},
1047 {"version", no_argument, 0, 'V'}, 1209 {"verbose", no_argument, 0, 'v'},
1048 {"help", no_argument, 0, 'h'}, 1210 {"version", no_argument, 0, 'V'},
1049 {0, 0, 0, 0}}; 1211 {"help", no_argument, 0, 'h'},
1050 1212 {"output-format", required_argument, 0, output_format_index},
1051 int c = 0; 1213 {0, 0, 0, 0}};
1214
1215 check_dhcp_config config = check_dhcp_config_init();
1216 int option_char = 0;
1052 while (true) { 1217 while (true) {
1053 c = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index); 1218 option_char = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index);
1054 1219
1055 if (c == -1 || c == EOF || c == 1) 1220 if (option_char == -1 || option_char == EOF || option_char == 1) {
1056 break; 1221 break;
1222 }
1057 1223
1058 switch (c) { 1224 switch (option_char) {
1059
1060 case 's': /* DHCP server address */ 1225 case 's': /* DHCP server address */
1061 resolve_host(optarg, &dhcp_ip); 1226 resolve_host(optarg, &config.dhcp_ip);
1062 add_requested_server(dhcp_ip); 1227 add_requested_server(config.dhcp_ip, &config.num_of_requested_servers,
1228 &config.requested_server_list);
1063 break; 1229 break;
1064 1230
1065 case 'r': /* address we are requested from DHCP servers */ 1231 case 'r': /* address we are requested from DHCP servers */
1066 resolve_host(optarg, &requested_address); 1232 resolve_host(optarg, &config.requested_address);
1067 request_specific_address = true; 1233 config.request_specific_address = true;
1068 break; 1234 break;
1069 1235
1070 case 't': /* timeout */ 1236 case 't': /* timeout */
1071 1237 if (atoi(optarg) > 0) {
1072 /* 1238 config.dhcpoffer_timeout = atoi(optarg);
1073 if(is_intnonneg(optarg)) 1239 }
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; 1240 break;
1082 1241
1083 case 'm': /* MAC address */ 1242 case 'm': /* MAC address */
1084 1243 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"); 1244 usage("Cannot parse MAC address.\n");
1087 if (verbose) 1245 }
1088 print_hardware_address(user_specified_mac); 1246 if (verbose) {
1089 1247 print_hardware_address(config.user_specified_mac);
1248 }
1090 break; 1249 break;
1091 1250
1092 case 'i': /* interface name */ 1251 case 'i': /* interface name */
1093 1252 strncpy(config.network_interface_name, optarg,
1094 strncpy(network_interface_name, optarg, sizeof(network_interface_name) - 1); 1253 sizeof(config.network_interface_name) - 1);
1095 network_interface_name[sizeof(network_interface_name) - 1] = '\x0'; 1254 config.network_interface_name[sizeof(config.network_interface_name) - 1] = '\x0';
1096
1097 break; 1255 break;
1098 1256
1099 case 'u': /* unicast testing */ 1257 case 'u': /* unicast testing */
1100 unicast = true; 1258 config.unicast_mode = true;
1101 break; 1259 break;
1260
1102 case 'x': /* exclusive testing aka "rogue DHCP server detection" */ 1261 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1103 exclusive = true; 1262 config.exclusive_mode = true;
1104 break; 1263 break;
1105 1264
1106 case 'V': /* version */ 1265 case 'V': /* version */
@@ -1114,6 +1273,18 @@ static int call_getopt(int argc, char **argv) {
1114 case 'v': /* verbose */ 1273 case 'v': /* verbose */
1115 verbose = 1; 1274 verbose = 1;
1116 break; 1275 break;
1276 case output_format_index: {
1277 parsed_output_format parser = mp_parse_output_format(optarg);
1278 if (!parser.parsing_success) {
1279 // TODO List all available formats here, maybe add anothoer usage function
1280 printf("Invalid output format: %s\n", optarg);
1281 exit(STATE_UNKNOWN);
1282 }
1283
1284 config.output_format_is_set = true;
1285 config.output_format = parser.output_format;
1286 break;
1287 }
1117 case '?': /* help */ 1288 case '?': /* help */
1118 usage5(); 1289 usage5();
1119 break; 1290 break;
@@ -1122,15 +1293,16 @@ static int call_getopt(int argc, char **argv) {
1122 break; 1293 break;
1123 } 1294 }
1124 } 1295 }
1125 return optind;
1126}
1127 1296
1128static int validate_arguments(int argc) { 1297 if (argc - optind > 0) {
1129
1130 if (argc - optind > 0)
1131 usage(_("Got unexpected non-option argument")); 1298 usage(_("Got unexpected non-option argument"));
1299 }
1132 1300
1133 return OK; 1301 process_arguments_wrapper result = {
1302 .config = config,
1303 .error = OK,
1304 };
1305 return result;
1134} 1306}
1135 1307
1136#if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1308#if defined(__sun__) || defined(__solaris__) || defined(__hpux__)
@@ -1180,7 +1352,8 @@ static int put_ctrl(int fd, int len, int pri) {
1180 1352
1181 ctl.len = len; 1353 ctl.len = len;
1182 if (putmsg(fd, &ctl, 0, pri) < 0) { 1354 if (putmsg(fd, &ctl, 0, pri) < 0) {
1183 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"), strerror(errno)); 1355 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"),
1356 strerror(errno));
1184 exit(STATE_UNKNOWN); 1357 exit(STATE_UNKNOWN);
1185 } 1358 }
1186 1359
@@ -1193,7 +1366,8 @@ static int put_both(int fd, int clen, int dlen, int pri) {
1193 ctl.len = clen; 1366 ctl.len = clen;
1194 dat.len = dlen; 1367 dat.len = dlen;
1195 if (putmsg(fd, &ctl, &dat, pri) < 0) { 1368 if (putmsg(fd, &ctl, &dat, pri) < 0) {
1196 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"), strerror(errno)); 1369 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"),
1370 strerror(errno));
1197 exit(STATE_UNKNOWN); 1371 exit(STATE_UNKNOWN);
1198 } 1372 }
1199 1373
@@ -1205,7 +1379,8 @@ static int dl_open(const char *dev, int unit, int *fd) {
1205 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; 1379 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area;
1206 1380
1207 if ((*fd = open(dev, O_RDWR)) == -1) { 1381 if ((*fd = open(dev, O_RDWR)) == -1) {
1208 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"), dev, strerror(errno)); 1382 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"),
1383 dev, strerror(errno));
1209 exit(STATE_UNKNOWN); 1384 exit(STATE_UNKNOWN);
1210 } 1385 }
1211 attach_req->dl_primitive = DL_ATTACH_REQ; 1386 attach_req->dl_primitive = DL_ATTACH_REQ;
@@ -1229,7 +1404,8 @@ static int dl_bind(int fd, int sap, u_char *addr) {
1229 put_ctrl(fd, sizeof(dl_bind_req_t), 0); 1404 put_ctrl(fd, sizeof(dl_bind_req_t), 0);
1230 get_msg(fd); 1405 get_msg(fd);
1231 if (GOT_ERR == check_ctrl(DL_BIND_ACK)) { 1406 if (GOT_ERR == check_ctrl(DL_BIND_ACK)) {
1232 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"), strerror(errno)); 1407 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"),
1408 strerror(errno));
1233 exit(STATE_UNKNOWN); 1409 exit(STATE_UNKNOWN);
1234 } 1410 }
1235 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length); 1411 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length);
@@ -1249,7 +1425,7 @@ static int dl_bind(int fd, int sap, u_char *addr) {
1249 * 1425 *
1250 ***********************************************************************/ 1426 ***********************************************************************/
1251 1427
1252static long mac_addr_dlpi(const char *dev, int unit, u_char *addr) { 1428long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1253 int fd; 1429 int fd;
1254 u_char mac_addr[25]; 1430 u_char mac_addr[25];
1255 1431
@@ -1268,51 +1444,53 @@ static long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1268#endif 1444#endif
1269 1445
1270/* resolve host name or die (TODO: move this to netutils.c!) */ 1446/* resolve host name or die (TODO: move this to netutils.c!) */
1271static void resolve_host(const char *in, struct in_addr *out) { 1447void resolve_host(const char *name, struct in_addr *out) {
1272 struct addrinfo hints, *ai; 1448 struct addrinfo hints = {
1449 .ai_family = PF_INET,
1450 };
1451 struct addrinfo *addr_info;
1273 1452
1274 memset(&hints, 0, sizeof(hints)); 1453 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); 1454 usage_va(_("Invalid hostname/address - %s"), optarg);
1455 }
1278 1456
1279 memcpy(out, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(*out)); 1457 memcpy(out, &((struct sockaddr_in *)addr_info->ai_addr)->sin_addr, sizeof(*out));
1280 freeaddrinfo(ai); 1458 freeaddrinfo(addr_info);
1281} 1459}
1282 1460
1283/* parse MAC address string, return 6 bytes (unterminated) or NULL */ 1461/* parse MAC address string, return 6 bytes (unterminated) or NULL */
1284static unsigned char *mac_aton(const char *string) { 1462unsigned char *mac_aton(const char *string) {
1285 static unsigned char result[6]; 1463 static unsigned char result[MAC_ADDR_LEN];
1286 char tmp[3]; 1464 char tmp[3];
1287 unsigned i, j; 1465 unsigned byte_counter = 0;
1288 1466
1289 for (i = 0, j = 0; string[i] != '\0' && j < sizeof(result); i++) { 1467 for (int i = 0; string[i] != '\0' && byte_counter < sizeof(result); i++) {
1290 /* ignore ':' and any other non-hex character */ 1468 /* ignore ':' and any other non-hex character */
1291 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) 1469 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) {
1292 continue; 1470 continue;
1471 }
1293 tmp[0] = string[i]; 1472 tmp[0] = string[i];
1294 tmp[1] = string[i + 1]; 1473 tmp[1] = string[i + 1];
1295 tmp[2] = '\0'; 1474 tmp[2] = '\0';
1296 result[j] = strtol(tmp, (char **)NULL, 16); 1475 result[byte_counter] = strtol(tmp, (char **)NULL, 16);
1297 i++; 1476 i++;
1298 j++; 1477 byte_counter++;
1299 } 1478 }
1300 1479
1301 return (j == 6) ? result : NULL; 1480 return (byte_counter == MAC_ADDR_LEN) ? result : NULL;
1302} 1481}
1303 1482
1304static void print_hardware_address(const unsigned char *address) { 1483void print_hardware_address(const unsigned char *address) {
1305 int i;
1306 1484
1307 printf(_("Hardware address: ")); 1485 printf(_("Hardware address: "));
1308 for (i = 0; i < 5; i++) 1486 for (int addr_idx = 0; addr_idx < MAC_ADDR_LEN; addr_idx++) {
1309 printf("%2.2x:", address[i]); 1487 printf("%2.2x:", address[addr_idx]);
1310 printf("%2.2x", address[i]); 1488 }
1311 putchar('\n'); 1489 putchar('\n');
1312} 1490}
1313 1491
1314/* print usage help */ 1492/* print usage help */
1315static void print_help(void) { 1493void print_help(void) {
1316 1494
1317 print_revision(progname, NP_VERSION); 1495 print_revision(progname, NP_VERSION);
1318 1496
@@ -1328,6 +1506,7 @@ static void print_help(void) {
1328 printf(UT_HELP_VRSN); 1506 printf(UT_HELP_VRSN);
1329 printf(UT_EXTRA_OPTS); 1507 printf(UT_EXTRA_OPTS);
1330 1508
1509 printf(UT_OUTPUT_FORMAT);
1331 printf(UT_VERBOSE); 1510 printf(UT_VERBOSE);
1332 1511
1333 printf(" %s\n", "-s, --serverip=IPADDRESS"); 1512 printf(" %s\n", "-s, --serverip=IPADDRESS");
@@ -1343,10 +1522,10 @@ static void print_help(void) {
1343 printf(" %s\n", "-u, --unicast"); 1522 printf(" %s\n", "-u, --unicast");
1344 printf(" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s")); 1523 printf(" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s"));
1345 printf(" %s\n", "-x, --exclusive"); 1524 printf(" %s\n", "-x, --exclusive");
1346 printf(" %s\n", _("Only requested DHCP server may response (rogue DHCP server detection), requires -s")); 1525 printf(" %s\n",
1526 _("Only requested DHCP server may response (rogue DHCP server detection), requires -s"));
1347 1527
1348 printf(UT_SUPPORT); 1528 printf(UT_SUPPORT);
1349 return;
1350} 1529}
1351 1530
1352void print_usage(void) { 1531void print_usage(void) {
@@ -1354,6 +1533,4 @@ void print_usage(void) {
1354 printf("%s\n", _("Usage:")); 1533 printf("%s\n", _("Usage:"));
1355 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname); 1534 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname);
1356 printf(" [-i interface] [-m mac]\n"); 1535 printf(" [-i interface] [-m mac]\n");
1357
1358 return;
1359} 1536}
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/check_icmp.c b/plugins-root/check_icmp.c
index 55405b8a..d46d2ccc 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -151,10 +151,9 @@ static void set_source_ip(char *arg, int icmp_sock, sa_family_t addr_family);
151 151
152/* Receiving data */ 152/* Receiving data */
153static int wait_for_reply(check_icmp_socket_set sockset, time_t time_interval, 153static int wait_for_reply(check_icmp_socket_set sockset, time_t time_interval,
154 unsigned short icmp_pkt_size, time_t *pkt_interval, 154 unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
155 time_t *target_interval, uint16_t sender_id, ping_target **table, 155 ping_target **table, unsigned short packets,
156 unsigned short packets, unsigned short number_of_targets, 156 unsigned short number_of_targets, check_icmp_state *program_state);
157 check_icmp_state *program_state);
158 157
159typedef struct { 158typedef struct {
160 sa_family_t recv_proto; 159 sa_family_t recv_proto;
@@ -164,9 +163,9 @@ static recvfrom_wto_wrapper recvfrom_wto(check_icmp_socket_set sockset, void *bu
164 struct sockaddr *saddr, time_t *timeout, 163 struct sockaddr *saddr, time_t *timeout,
165 struct timeval *received_timestamp); 164 struct timeval *received_timestamp);
166static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, 165static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
167 time_t *pkt_interval, time_t *target_interval, uint16_t sender_id, 166 time_t *target_interval, uint16_t sender_id, ping_target **table,
168 ping_target **table, unsigned short packets, 167 unsigned short packets, unsigned short number_of_targets,
169 unsigned short number_of_targets, check_icmp_state *program_state); 168 check_icmp_state *program_state);
170 169
171/* Sending data */ 170/* Sending data */
172static int send_icmp_ping(check_icmp_socket_set sockset, ping_target *host, 171static int send_icmp_ping(check_icmp_socket_set sockset, ping_target *host,
@@ -198,11 +197,11 @@ static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_s
198 threshold_mode mode); 197 threshold_mode mode);
199 198
200/* main test function */ 199/* main test function */
201static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, 200static void run_checks(unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
202 uint16_t sender_id, check_icmp_execution_mode mode, 201 check_icmp_execution_mode mode, time_t max_completion_time,
203 time_t max_completion_time, struct timeval prog_start, ping_target **table, 202 struct timeval prog_start, ping_target **table, unsigned short packets,
204 unsigned short packets, check_icmp_socket_set sockset, 203 check_icmp_socket_set sockset, unsigned short number_of_targets,
205 unsigned short number_of_targets, check_icmp_state *program_state); 204 check_icmp_state *program_state);
206mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, 205mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
207 check_icmp_threshold warn, check_icmp_threshold crit); 206 check_icmp_threshold warn, check_icmp_threshold crit);
208 207
@@ -297,14 +296,12 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
297 result.config.mode = MODE_ICMP; 296 result.config.mode = MODE_ICMP;
298 } else if (!strcmp(progname, "check_host")) { 297 } else if (!strcmp(progname, "check_host")) {
299 result.config.mode = MODE_HOSTCHECK; 298 result.config.mode = MODE_HOSTCHECK;
300 result.config.pkt_interval = 1000000;
301 result.config.number_of_packets = 5; 299 result.config.number_of_packets = 5;
302 result.config.crit.rta = result.config.warn.rta = 1000000; 300 result.config.crit.rta = result.config.warn.rta = 1000000;
303 result.config.crit.pl = result.config.warn.pl = 100; 301 result.config.crit.pl = result.config.warn.pl = 100;
304 } else if (!strcmp(progname, "check_rta_multi")) { 302 } else if (!strcmp(progname, "check_rta_multi")) {
305 result.config.mode = MODE_ALL; 303 result.config.mode = MODE_ALL;
306 result.config.target_interval = 0; 304 result.config.target_interval = 0;
307 result.config.pkt_interval = 50000;
308 result.config.number_of_packets = 5; 305 result.config.number_of_packets = 5;
309 } 306 }
310 /* support "--help" and "--version" */ 307 /* support "--help" and "--version" */
@@ -319,13 +316,44 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
319 316
320 sa_family_t enforced_ai_family = AF_UNSPEC; 317 sa_family_t enforced_ai_family = AF_UNSPEC;
321 318
319 enum {
320 output_format_index = CHAR_MAX + 1,
321 };
322
323 struct option longopts[] = {
324 {"version", no_argument, 0, 'V'},
325 {"help", no_argument, 0, 'h'},
326 {"verbose", no_argument, 0, 'v'},
327 {"Host", required_argument, 0, 'H'},
328 {"ipv4-only", no_argument, 0, '4'},
329 {"ipv6-only", no_argument, 0, '6'},
330 {"warning", required_argument, 0, 'w'},
331 {"critical", required_argument, 0, 'c'},
332 {"rta-mode-thresholds", required_argument, 0, 'R'},
333 {"packet-loss-mode-thresholds", required_argument, 0, 'P'},
334 {"jitter-mode-thresholds", required_argument, 0, 'J'},
335 {"mos-mode-thresholds", required_argument, 0, 'M'},
336 {"score-mode-thresholds", required_argument, 0, 'S'},
337 {"out-of-order-packets", no_argument, 0, 'O'},
338 {"number-of-packets", required_argument, 0, 'n'},
339 {"number-of-packets", required_argument, 0, 'p'},
340 {"packet-interval", required_argument, 0, 'i'},
341 {"target-interval", required_argument, 0, 'I'},
342 {"minimal-host-alive", required_argument, 0, 'm'},
343 {"outgoing-ttl", required_argument, 0, 'l'},
344 {"size", required_argument, 0, 'b'},
345 {"output-format", required_argument, 0, output_format_index},
346 {},
347 };
348
322 // Parse protocol arguments first 349 // Parse protocol arguments first
323 // and count hosts here 350 // and count hosts here
324 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64"; 351 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
325 for (int i = 1; i < argc; i++) { 352 for (int i = 1; i < argc; i++) {
326 long int arg; 353 long int arg;
327 while ((arg = getopt(argc, argv, opts_str)) != EOF) { 354 while ((arg = getopt_long(argc, argv, opts_str, longopts, NULL)) != EOF) {
328 switch (arg) { 355 switch (arg) {
356
329 case '4': 357 case '4':
330 if (enforced_ai_family != AF_UNSPEC) { 358 if (enforced_ai_family != AF_UNSPEC) {
331 crash("Multiple protocol versions not supported"); 359 crash("Multiple protocol versions not supported");
@@ -342,6 +370,11 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
342 result.config.number_of_hosts++; 370 result.config.number_of_hosts++;
343 break; 371 break;
344 } 372 }
373 case 'h': /* help */
374 // Trigger help here to avoid adding hosts before that (and doing DNS queries)
375 print_help();
376 exit(STATE_UNKNOWN);
377 break;
345 case 'v': 378 case 'v':
346 debug++; 379 debug++;
347 break; 380 break;
@@ -374,14 +407,13 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
374 /* parse the arguments */ 407 /* parse the arguments */
375 for (int i = 1; i < argc; i++) { 408 for (int i = 1; i < argc; i++) {
376 long int arg; 409 long int arg;
377 while ((arg = getopt(argc, argv, opts_str)) != EOF) { 410 while ((arg = getopt_long(argc, argv, opts_str, longopts, NULL)) != EOF) {
378 switch (arg) { 411 switch (arg) {
379 case 'b': { 412 case 'b': {
380 long size = strtol(optarg, NULL, 0); 413 long size = strtol(optarg, NULL, 0);
381 if ((unsigned long)size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && 414 if ((unsigned long)size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
382 size < MAX_PING_DATA) { 415 size < MAX_PING_DATA) {
383 result.config.icmp_data_size = (unsigned short)size; 416 result.config.icmp_data_size = (unsigned short)size;
384 result.config.icmp_pkt_size = (unsigned short)(size + ICMP_MINLEN);
385 } else { 417 } else {
386 usage_va("ICMP data length must be between: %lu and %lu", 418 usage_va("ICMP data length must be between: %lu and %lu",
387 sizeof(struct icmp) + sizeof(struct icmp_ping_data), 419 sizeof(struct icmp) + sizeof(struct icmp_ping_data),
@@ -389,13 +421,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
389 } 421 }
390 } break; 422 } break;
391 case 'i': { 423 case 'i': {
392 get_timevar_wrapper parsed_time = get_timevar(optarg); 424 // packet_interval was unused and is now removed
393
394 if (parsed_time.error_code == OK) {
395 result.config.pkt_interval = parsed_time.time_range;
396 } else {
397 crash("failed to parse packet interval");
398 }
399 } break; 425 } break;
400 case 'I': { 426 case 'I': {
401 get_timevar_wrapper parsed_time = get_timevar(optarg); 427 get_timevar_wrapper parsed_time = get_timevar(optarg);
@@ -455,7 +481,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
455 result.config.need_v6 = true; 481 result.config.need_v6 = true;
456 } 482 }
457 } else { 483 } else {
458 // TODO adding host failed, crash here 484 crash("Failed to add host, unable to parse it correctly");
459 } 485 }
460 } break; 486 } break;
461 case 'l': 487 case 'l':
@@ -470,10 +496,6 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
470 case 'V': /* version */ 496 case 'V': /* version */
471 print_revision(progname, NP_VERSION); 497 print_revision(progname, NP_VERSION);
472 exit(STATE_UNKNOWN); 498 exit(STATE_UNKNOWN);
473 case 'h': /* help */
474 print_help();
475 exit(STATE_UNKNOWN);
476 break;
477 case 'R': /* RTA mode */ { 499 case 'R': /* RTA mode */ {
478 get_threshold2_wrapper rta_th = get_threshold2( 500 get_threshold2_wrapper rta_th = get_threshold2(
479 optarg, strlen(optarg), result.config.warn, result.config.crit, const_rta_mode); 501 optarg, strlen(optarg), result.config.warn, result.config.crit, const_rta_mode);
@@ -536,6 +558,18 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) {
536 case 'O': /* out of order mode */ 558 case 'O': /* out of order mode */
537 result.config.modes.order_mode = true; 559 result.config.modes.order_mode = true;
538 break; 560 break;
561 case output_format_index: {
562 parsed_output_format parser = mp_parse_output_format(optarg);
563 if (!parser.parsing_success) {
564 // TODO List all available formats here, maybe add anothoer usage function
565 printf("Invalid output format: %s\n", optarg);
566 exit(STATE_UNKNOWN);
567 }
568
569 result.config.output_format_is_set = true;
570 result.config.output_format = parser.output_format;
571 break;
572 }
539 } 573 }
540 } 574 }
541 } 575 }
@@ -697,8 +731,8 @@ static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icm
697} 731}
698 732
699static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, 733static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
700 time_t *pkt_interval, time_t *target_interval, 734 time_t *target_interval, const uint16_t sender_id,
701 const uint16_t sender_id, ping_target **table, unsigned short packets, 735 ping_target **table, unsigned short packets,
702 const unsigned short number_of_targets, 736 const unsigned short number_of_targets,
703 check_icmp_state *program_state) { 737 check_icmp_state *program_state) {
704 struct icmp icmp_packet; 738 struct icmp icmp_packet;
@@ -758,7 +792,6 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
758 /* source quench means we're sending too fast, so increase the 792 /* source quench means we're sending too fast, so increase the
759 * interval and mark this packet lost */ 793 * interval and mark this packet lost */
760 if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) { 794 if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) {
761 *pkt_interval = (unsigned int)((double)*pkt_interval * PACKET_BACKOFF_FACTOR);
762 *target_interval = (unsigned int)((double)*target_interval * TARGET_BACKOFF_FACTOR); 795 *target_interval = (unsigned int)((double)*target_interval * TARGET_BACKOFF_FACTOR);
763 } else { 796 } else {
764 program_state->targets_down++; 797 program_state->targets_down++;
@@ -803,18 +836,9 @@ int main(int argc, char **argv) {
803 836
804 const check_icmp_config config = tmp_config.config; 837 const check_icmp_config config = tmp_config.config;
805 838
806 // int icmp_proto = IPPROTO_ICMP; 839 if (config.output_format_is_set) {
807 // add_target might change address_family 840 mp_set_format(config.output_format);
808 // switch (address_family) { 841 }
809 // case AF_INET:
810 // icmp_proto = IPPROTO_ICMP;
811 // break;
812 // case AF_INET6:
813 // icmp_proto = IPPROTO_ICMPV6;
814 // break;
815 // default:
816 // crash("Address family not supported");
817 // }
818 842
819 check_icmp_socket_set sockset = { 843 check_icmp_socket_set sockset = {
820 .socket4 = -1, 844 .socket4 = -1,
@@ -899,18 +923,17 @@ int main(int argc, char **argv) {
899 gettimeofday(&prog_start, NULL); 923 gettimeofday(&prog_start, NULL);
900 924
901 time_t max_completion_time = 925 time_t max_completion_time =
902 ((config.pkt_interval * config.number_of_targets * config.number_of_packets) + 926 (config.target_interval * config.number_of_targets) +
903 (config.target_interval * config.number_of_targets)) +
904 (config.crit.rta * config.number_of_targets * config.number_of_packets) + config.crit.rta; 927 (config.crit.rta * config.number_of_targets * config.number_of_packets) + config.crit.rta;
905 928
906 if (debug) { 929 if (debug) {
907 printf("packets: %u, targets: %u\n" 930 printf("packets: %u, targets: %u\n"
908 "target_interval: %0.3f, pkt_interval %0.3f\n" 931 "target_interval: %0.3f\n"
909 "crit.rta: %0.3f\n" 932 "crit.rta: %0.3f\n"
910 "max_completion_time: %0.3f\n", 933 "max_completion_time: %0.3f\n",
911 config.number_of_packets, config.number_of_targets, 934 config.number_of_packets, config.number_of_targets,
912 (float)config.target_interval / 1000, (float)config.pkt_interval / 1000, 935 (float)config.target_interval / 1000, (float)config.crit.rta / 1000,
913 (float)config.crit.rta / 1000, (float)max_completion_time / 1000); 936 (float)max_completion_time / 1000);
914 } 937 }
915 938
916 if (debug) { 939 if (debug) {
@@ -923,9 +946,8 @@ int main(int argc, char **argv) {
923 if (debug) { 946 if (debug) {
924 printf("crit = {%ld, %u%%}, warn = {%ld, %u%%}\n", config.crit.rta, config.crit.pl, 947 printf("crit = {%ld, %u%%}, warn = {%ld, %u%%}\n", config.crit.rta, config.crit.pl,
925 config.warn.rta, config.warn.pl); 948 config.warn.rta, config.warn.pl);
926 printf("pkt_interval: %ld target_interval: %ld\n", config.pkt_interval, 949 printf("target_interval: %ld\n", config.target_interval);
927 config.target_interval); 950 printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_data_size + ICMP_MINLEN, timeout);
928 printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_pkt_size, timeout);
929 } 951 }
930 952
931 if (config.min_hosts_alive < -1) { 953 if (config.min_hosts_alive < -1) {
@@ -948,14 +970,13 @@ int main(int argc, char **argv) {
948 target_index++; 970 target_index++;
949 } 971 }
950 972
951 time_t pkt_interval = config.pkt_interval;
952 time_t target_interval = config.target_interval; 973 time_t target_interval = config.target_interval;
953 974
954 check_icmp_state program_state = check_icmp_state_init(); 975 check_icmp_state program_state = check_icmp_state_init();
955 976
956 run_checks(config.icmp_data_size, &pkt_interval, &target_interval, config.sender_id, 977 run_checks(config.icmp_data_size, &target_interval, config.sender_id, config.mode,
957 config.mode, max_completion_time, prog_start, table, config.number_of_packets, 978 max_completion_time, prog_start, table, config.number_of_packets, sockset,
958 sockset, config.number_of_targets, &program_state); 979 config.number_of_targets, &program_state);
959 980
960 errno = 0; 981 errno = 0;
961 982
@@ -974,7 +995,7 @@ int main(int argc, char **argv) {
974 mp_exit(overall); 995 mp_exit(overall);
975} 996}
976 997
977static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, 998static void run_checks(unsigned short icmp_pkt_size, time_t *target_interval,
978 const uint16_t sender_id, const check_icmp_execution_mode mode, 999 const uint16_t sender_id, const check_icmp_execution_mode mode,
979 const time_t max_completion_time, const struct timeval prog_start, 1000 const time_t max_completion_time, const struct timeval prog_start,
980 ping_target **table, const unsigned short packets, 1001 ping_target **table, const unsigned short packets,
@@ -1007,17 +1028,15 @@ static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_
1007 if (targets_alive(number_of_targets, program_state->targets_down) || 1028 if (targets_alive(number_of_targets, program_state->targets_down) ||
1008 get_timevaldiff(prog_start, prog_start) < max_completion_time || 1029 get_timevaldiff(prog_start, prog_start) < max_completion_time ||
1009 !(mode == MODE_HOSTCHECK && program_state->targets_down)) { 1030 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1010 wait_for_reply(sockset, *target_interval, icmp_pkt_size, pkt_interval, 1031 wait_for_reply(sockset, *target_interval, icmp_pkt_size, target_interval, sender_id,
1011 target_interval, sender_id, table, packets, number_of_targets, 1032 table, packets, number_of_targets, program_state);
1012 program_state);
1013 } 1033 }
1014 } 1034 }
1015 if (targets_alive(number_of_targets, program_state->targets_down) || 1035 if (targets_alive(number_of_targets, program_state->targets_down) ||
1016 get_timevaldiff_to_now(prog_start) < max_completion_time || 1036 get_timevaldiff_to_now(prog_start) < max_completion_time ||
1017 !(mode == MODE_HOSTCHECK && program_state->targets_down)) { 1037 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1018 wait_for_reply(sockset, *pkt_interval * number_of_targets, icmp_pkt_size, pkt_interval, 1038 wait_for_reply(sockset, number_of_targets, icmp_pkt_size, target_interval, sender_id,
1019 target_interval, sender_id, table, packets, number_of_targets, 1039 table, packets, number_of_targets, program_state);
1020 program_state);
1021 } 1040 }
1022 } 1041 }
1023 1042
@@ -1047,8 +1066,8 @@ static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_
1047 if (targets_alive(number_of_targets, program_state->targets_down) || 1066 if (targets_alive(number_of_targets, program_state->targets_down) ||
1048 get_timevaldiff_to_now(prog_start) < max_completion_time || 1067 get_timevaldiff_to_now(prog_start) < max_completion_time ||
1049 !(mode == MODE_HOSTCHECK && program_state->targets_down)) { 1068 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1050 wait_for_reply(sockset, final_wait, icmp_pkt_size, pkt_interval, target_interval, 1069 wait_for_reply(sockset, final_wait, icmp_pkt_size, target_interval, sender_id, table,
1051 sender_id, table, packets, number_of_targets, program_state); 1070 packets, number_of_targets, program_state);
1052 } 1071 }
1053 } 1072 }
1054} 1073}
@@ -1064,10 +1083,9 @@ static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_
1064 * icmp echo reply : the rest 1083 * icmp echo reply : the rest
1065 */ 1084 */
1066static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_interval, 1085static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_interval,
1067 unsigned short icmp_pkt_size, time_t *pkt_interval, 1086 unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
1068 time_t *target_interval, uint16_t sender_id, ping_target **table, 1087 ping_target **table, const unsigned short packets,
1069 const unsigned short packets, const unsigned short number_of_targets, 1088 const unsigned short number_of_targets, check_icmp_state *program_state) {
1070 check_icmp_state *program_state) {
1071 union icmp_packet packet; 1089 union icmp_packet packet;
1072 if (!(packet.buf = malloc(icmp_pkt_size))) { 1090 if (!(packet.buf = malloc(icmp_pkt_size))) {
1073 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); 1091 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size);
@@ -1153,8 +1171,8 @@ static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_inter
1153 printf("not a proper ICMP_ECHOREPLY\n"); 1171 printf("not a proper ICMP_ECHOREPLY\n");
1154 } 1172 }
1155 1173
1156 handle_random_icmp(buf + hlen, &resp_addr, pkt_interval, target_interval, sender_id, 1174 handle_random_icmp(buf + hlen, &resp_addr, target_interval, sender_id, table, packets,
1157 table, packets, number_of_targets, program_state); 1175 number_of_targets, program_state);
1158 1176
1159 continue; 1177 continue;
1160 } 1178 }
@@ -1511,14 +1529,6 @@ static void finish(int sig, check_icmp_mode_switches modes, int min_hosts_alive,
1511 mp_add_subcheck_to_check(overall, host_check.sc_host); 1529 mp_add_subcheck_to_check(overall, host_check.sc_host);
1512 } 1530 }
1513 1531
1514 /* this is inevitable */
1515 // if (targets_alive(number_of_targets, program_state->targets_down) == 0) {
1516 // mp_subcheck sc_no_target_alive = mp_subcheck_init();
1517 // sc_no_target_alive = mp_set_subcheck_state(sc_no_target_alive, STATE_CRITICAL);
1518 // sc_no_target_alive.output = strdup("No target is alive!");
1519 // mp_add_subcheck_to_check(overall, sc_no_target_alive);
1520 // }
1521
1522 if (min_hosts_alive > -1) { 1532 if (min_hosts_alive > -1) {
1523 mp_subcheck sc_min_targets_alive = mp_subcheck_init(); 1533 mp_subcheck sc_min_targets_alive = mp_subcheck_init();
1524 sc_min_targets_alive = mp_set_subcheck_default_state(sc_min_targets_alive, STATE_OK); 1534 sc_min_targets_alive = mp_set_subcheck_default_state(sc_min_targets_alive, STATE_OK);
@@ -2045,77 +2055,77 @@ unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) {
2045} 2055}
2046 2056
2047void print_help(void) { 2057void print_help(void) {
2048 /*print_revision (progname);*/ /* FIXME: Why? */ 2058 // print_revision (progname); /* FIXME: Why? */
2049 printf("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n"); 2059 printf("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n");
2050 2060
2051 printf(COPYRIGHT, copyright, email); 2061 printf(COPYRIGHT, copyright, email);
2052 2062
2053 printf("\n\n");
2054
2055 print_usage(); 2063 print_usage();
2056 2064
2057 printf(UT_HELP_VRSN); 2065 printf(UT_HELP_VRSN);
2058 printf(UT_EXTRA_OPTS); 2066 printf(UT_EXTRA_OPTS);
2059 2067
2060 printf(" %s\n", "-H"); 2068 printf(" -H, --Host=HOST\n");
2061 printf(" %s\n", _("specify a target")); 2069 printf(" %s\n",
2062 printf(" %s\n", "[-4|-6]"); 2070 _("specify a target, might be one of: resolveable name | IPv6 address | IPv4 address\n"
2063 printf(" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets")); 2071 " (required, can be given multiple times)"));
2064 printf(" %s\n", "-w"); 2072 printf(" %s\n", "[-4|-6], [--ipv4-only|--ipv6-only]");
2065 printf(" %s", _("warning threshold (currently ")); 2073 printf(" %s\n", _("Use IPv4 or IPv6 only to communicate with the targets"));
2074 printf(" %s\n", "-w, --warning=WARN_VALUE");
2075 printf(" %s", _("warning threshold (default "));
2066 printf("%0.3fms,%u%%)\n", (float)DEFAULT_WARN_RTA / 1000, DEFAULT_WARN_PL); 2076 printf("%0.3fms,%u%%)\n", (float)DEFAULT_WARN_RTA / 1000, DEFAULT_WARN_PL);
2067 printf(" %s\n", "-c"); 2077 printf(" %s\n", "-c, --critical=CRIT_VALUE");
2068 printf(" %s", _("critical threshold (currently ")); 2078 printf(" %s", _("critical threshold (default "));
2069 printf("%0.3fms,%u%%)\n", (float)DEFAULT_CRIT_RTA / 1000, DEFAULT_CRIT_PL); 2079 printf("%0.3fms,%u%%)\n", (float)DEFAULT_CRIT_RTA / 1000, DEFAULT_CRIT_PL);
2070 2080
2071 printf(" %s\n", "-R"); 2081 printf(" %s\n", "-R, --rta-mode-thresholds=RTA_THRESHOLDS");
2072 printf(" %s\n", 2082 printf(" %s\n",
2073 _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms")); 2083 _("RTA (round trip average) mode warning,critical, ex. 100ms,200ms unit in ms"));
2074 printf(" %s\n", "-P"); 2084 printf(" %s\n", "-P, --packet-loss-mode-thresholds=PACKET_LOSS_THRESHOLD");
2075 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %")); 2085 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
2076 printf(" %s\n", "-J"); 2086 printf(" %s\n", "-J, --jitter-mode-thresholds=JITTER_MODE_THRESHOLD");
2077 printf(" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms ")); 2087 printf(" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms "));
2078 printf(" %s\n", "-M"); 2088 printf(" %s\n", "-M, --mos-mode-thresholds=MOS_MODE_THRESHOLD");
2079 printf(" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0")); 2089 printf(" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0"));
2080 printf(" %s\n", "-S"); 2090 printf(" %s\n", "-S, --score-mode-thresholds=SCORE_MODE_THRESHOLD");
2081 printf(" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 ")); 2091 printf(" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 "));
2082 printf(" %s\n", "-O"); 2092 printf(" %s\n", "-O, --out-of-order-packets");
2083 printf(" %s\n", _("detect out of order ICMP packts ")); 2093 printf(
2084 printf(" %s\n", "-H"); 2094 " %s\n",
2085 printf(" %s\n", _("specify a target")); 2095 _("detect out of order ICMP packets, if such packets are found, the result is CRITICAL"));
2086 printf(" %s\n", "-s"); 2096 printf(" %s\n", "[-n|-p], --number-of-packets=NUMBER_OF_PACKETS");
2087 printf(" %s\n", _("specify a source IP address or device name")); 2097 printf(" %s", _("number of packets to send (default "));
2088 printf(" %s\n", "-n");
2089 printf(" %s", _("number of packets to send (currently "));
2090 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS);
2091 printf(" %s\n", "-p");
2092 printf(" %s", _("number of packets to send (currently "));
2093 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS); 2098 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS);
2099
2094 printf(" %s\n", "-i"); 2100 printf(" %s\n", "-i");
2095 printf(" %s", _("max packet interval (currently ")); 2101 printf(" %s", _("[DEPRECATED] packet interval (default "));
2096 printf("%0.3fms)\n", (float)DEFAULT_PKT_INTERVAL / 1000); 2102 printf("%0.3fms)\n", (float)DEFAULT_PKT_INTERVAL / 1000);
2097 printf(" %s\n", "-I"); 2103 printf(" %s", _("This option was never actually used and is just mentioned here for "
2098 printf(" %s", _("max target interval (currently ")); 2104 "historical purposes\n"));
2099 printf("%0.3fms)\n", (float)DEFAULT_TARGET_INTERVAL / 1000); 2105
2100 printf(" %s\n", "-m"); 2106 printf(" %s\n", "-I, --target-interval=TARGET_INTERVAL");
2101 printf(" %s", _("number of alive hosts required for success")); 2107 printf(" %s%0.3fms)\n The time interval to wait in between one target and the next\n",
2108 _("max target interval (default "), (float)DEFAULT_TARGET_INTERVAL / 1000);
2109 printf(" %s\n", "-m, --minimal-host-alive=MIN_ALIVE");
2110 printf(" %s", _("number of alive hosts required for success. If less than MIN_ALIVE hosts "
2111 "are OK, but MIN_ALIVE hosts are WARNING or OK, WARNING, else CRITICAL"));
2102 printf("\n"); 2112 printf("\n");
2103 printf(" %s\n", "-l"); 2113 printf(" %s\n", "-l, --outgoing-ttl=OUTGOING_TTL");
2104 printf(" %s", _("TTL on outgoing packets (currently ")); 2114 printf(" %s", _("TTL on outgoing packets (default "));
2105 printf("%u)\n", DEFAULT_TTL); 2115 printf("%u)\n", DEFAULT_TTL);
2106 printf(" %s\n", "-t"); 2116 printf(" %s\n", "-b, --size=SIZE");
2107 printf(" %s", _("timeout value (seconds, currently ")); 2117 printf(" %s\n", _("Number of icmp ping data bytes to send"));
2108 printf("%u)\n", DEFAULT_TIMEOUT); 2118 printf(" %s %lu + %d)\n", _("Packet size will be SIZE + icmp header (default"),
2109 printf(" %s\n", "-b");
2110 printf(" %s\n", _("Number of icmp data bytes to send"));
2111 printf(" %s %lu + %d)\n", _("Packet size will be data bytes + icmp header (currently"),
2112 DEFAULT_PING_DATA_SIZE, ICMP_MINLEN); 2119 DEFAULT_PING_DATA_SIZE, ICMP_MINLEN);
2113 printf(" %s\n", "-v"); 2120 printf(" %s\n", "-v, --verbose");
2114 printf(" %s\n", _("verbose")); 2121 printf(" %s\n", _("Verbosity, can be given multiple times (for debugging)"));
2122
2123 printf(UT_OUTPUT_FORMAT);
2124
2115 printf("\n"); 2125 printf("\n");
2116 printf("%s\n", _("Notes:")); 2126 printf("%s\n", _("Notes:"));
2117 printf(" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P")); 2127 printf(" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P"));
2118 printf(" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not.")); 2128 printf(" %s\n", _("Naming a host (or several) to check is not."));
2119 printf("\n"); 2129 printf("\n");
2120 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); 2130 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%"));
2121 printf(" %s\n", _("packet loss. The default values should work well for most users.")); 2131 printf(" %s\n", _("packet loss. The default values should work well for most users."));
@@ -2123,23 +2133,13 @@ void print_help(void) {
2123 _("You can specify different RTA factors using the standardized abbreviations")); 2133 _("You can specify different RTA factors using the standardized abbreviations"));
2124 printf(" %s\n", 2134 printf(" %s\n",
2125 _("us (microseconds), ms (milliseconds, default) or just plain s for seconds.")); 2135 _("us (microseconds), ms (milliseconds, default) or just plain s for seconds."));
2126 /* -d not yet implemented */
2127 /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12
2128 hops")); printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent.")); printf
2129 ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do
2130 not."));*/
2131 printf("\n");
2132 printf(" %s\n", _("The -v switch can be specified several times for increased verbosity."));
2133 /* printf ("%s\n", _("Long options are currently unsupported."));
2134 printf ("%s\n", _("Options marked with * require an argument"));
2135 */
2136 2136
2137 printf(UT_SUPPORT); 2137 printf(UT_SUPPORT);
2138} 2138}
2139 2139
2140void print_usage(void) { 2140void print_usage(void) {
2141 printf("%s\n", _("Usage:")); 2141 printf("%s\n", _("Usage:"));
2142 printf(" %s [options] [-H] host1 host2 hostN\n", progname); 2142 printf(" %s [options] [-H host1 [-H host2 [-H hostN]]]\n", progname);
2143} 2143}
2144 2144
2145static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode, 2145static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode,
@@ -2276,10 +2276,10 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2276 2276
2277 if (rta >= crit.rta) { 2277 if (rta >= crit.rta) {
2278 sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL); 2278 sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL);
2279 xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, (double)crit.rta / 1000); 2279 xasprintf(&sc_rta.output, "%s >= %0.3fms", sc_rta.output, (double)crit.rta / 1000);
2280 } else if (rta >= warn.rta) { 2280 } else if (rta >= warn.rta) {
2281 sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING); 2281 sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING);
2282 xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, (double)warn.rta / 1000); 2282 xasprintf(&sc_rta.output, "%s >= %0.3fms", sc_rta.output, (double)warn.rta / 1000);
2283 } 2283 }
2284 2284
2285 if (packet_loss < 100) { 2285 if (packet_loss < 100) {
@@ -2316,10 +2316,10 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2316 2316
2317 if (packet_loss >= crit.pl) { 2317 if (packet_loss >= crit.pl) {
2318 sc_pl = mp_set_subcheck_state(sc_pl, STATE_CRITICAL); 2318 sc_pl = mp_set_subcheck_state(sc_pl, STATE_CRITICAL);
2319 xasprintf(&sc_pl.output, "%s > %u%%", sc_pl.output, crit.pl); 2319 xasprintf(&sc_pl.output, "%s >= %u%%", sc_pl.output, crit.pl);
2320 } else if (packet_loss >= warn.pl) { 2320 } else if (packet_loss >= warn.pl) {
2321 sc_pl = mp_set_subcheck_state(sc_pl, STATE_WARNING); 2321 sc_pl = mp_set_subcheck_state(sc_pl, STATE_WARNING);
2322 xasprintf(&sc_pl.output, "%s > %u%%", sc_pl.output, crit.pl); 2322 xasprintf(&sc_pl.output, "%s >= %u%%", sc_pl.output, warn.pl);
2323 } 2323 }
2324 2324
2325 mp_perfdata pd_pl = perfdata_init(); 2325 mp_perfdata pd_pl = perfdata_init();
@@ -2342,10 +2342,10 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2342 2342
2343 if (target.jitter >= crit.jitter) { 2343 if (target.jitter >= crit.jitter) {
2344 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_CRITICAL); 2344 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_CRITICAL);
2345 xasprintf(&sc_jitter.output, "%s > %0.3fms", sc_jitter.output, crit.jitter); 2345 xasprintf(&sc_jitter.output, "%s >= %0.3fms", sc_jitter.output, crit.jitter);
2346 } else if (target.jitter >= warn.jitter) { 2346 } else if (target.jitter >= warn.jitter) {
2347 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_WARNING); 2347 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_WARNING);
2348 xasprintf(&sc_jitter.output, "%s > %0.3fms", sc_jitter.output, warn.jitter); 2348 xasprintf(&sc_jitter.output, "%s >= %0.3fms", sc_jitter.output, warn.jitter);
2349 } 2349 }
2350 2350
2351 if (packet_loss < 100) { 2351 if (packet_loss < 100) {
@@ -2379,10 +2379,10 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2379 2379
2380 if (mos <= crit.mos) { 2380 if (mos <= crit.mos) {
2381 sc_mos = mp_set_subcheck_state(sc_mos, STATE_CRITICAL); 2381 sc_mos = mp_set_subcheck_state(sc_mos, STATE_CRITICAL);
2382 xasprintf(&sc_mos.output, "%s < %0.1f", sc_mos.output, crit.mos); 2382 xasprintf(&sc_mos.output, "%s <= %0.1f", sc_mos.output, crit.mos);
2383 } else if (mos <= warn.mos) { 2383 } else if (mos <= warn.mos) {
2384 sc_mos = mp_set_subcheck_state(sc_mos, STATE_WARNING); 2384 sc_mos = mp_set_subcheck_state(sc_mos, STATE_WARNING);
2385 xasprintf(&sc_mos.output, "%s < %0.1f", sc_mos.output, warn.mos); 2385 xasprintf(&sc_mos.output, "%s <= %0.1f", sc_mos.output, warn.mos);
2386 } 2386 }
2387 2387
2388 if (packet_loss < 100) { 2388 if (packet_loss < 100) {
@@ -2391,8 +2391,8 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2391 pd_mos.value = mp_create_pd_value(mos); 2391 pd_mos.value = mp_create_pd_value(mos);
2392 pd_mos.warn = mp_range_set_end(pd_mos.warn, mp_create_pd_value(warn.mos)); 2392 pd_mos.warn = mp_range_set_end(pd_mos.warn, mp_create_pd_value(warn.mos));
2393 pd_mos.crit = mp_range_set_end(pd_mos.crit, mp_create_pd_value(crit.mos)); 2393 pd_mos.crit = mp_range_set_end(pd_mos.crit, mp_create_pd_value(crit.mos));
2394 pd_mos.min = mp_create_pd_value(0); 2394 pd_mos.min = mp_create_pd_value(0); // MOS starts at 0
2395 pd_mos.max = mp_create_pd_value(5); 2395 pd_mos.max = mp_create_pd_value(5); // MOS max is 5, by definition
2396 mp_add_perfdata_to_subcheck(&sc_mos, pd_mos); 2396 mp_add_perfdata_to_subcheck(&sc_mos, pd_mos);
2397 } 2397 }
2398 mp_add_subcheck_to_subcheck(&result, sc_mos); 2398 mp_add_subcheck_to_subcheck(&result, sc_mos);
@@ -2405,10 +2405,10 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2405 2405
2406 if (score <= crit.score) { 2406 if (score <= crit.score) {
2407 sc_score = mp_set_subcheck_state(sc_score, STATE_CRITICAL); 2407 sc_score = mp_set_subcheck_state(sc_score, STATE_CRITICAL);
2408 xasprintf(&sc_score.output, "%s < %f", sc_score.output, crit.score); 2408 xasprintf(&sc_score.output, "%s <= %f", sc_score.output, crit.score);
2409 } else if (score <= warn.score) { 2409 } else if (score <= warn.score) {
2410 sc_score = mp_set_subcheck_state(sc_score, STATE_WARNING); 2410 sc_score = mp_set_subcheck_state(sc_score, STATE_WARNING);
2411 xasprintf(&sc_score.output, "%s < %f", sc_score.output, warn.score); 2411 xasprintf(&sc_score.output, "%s <= %f", sc_score.output, warn.score);
2412 } 2412 }
2413 2413
2414 if (packet_loss < 100) { 2414 if (packet_loss < 100) {
diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c
index ec786305..1b96a392 100644
--- a/plugins-root/check_icmp.d/check_icmp_helpers.c
+++ b/plugins-root/check_icmp.d/check_icmp_helpers.c
@@ -34,8 +34,6 @@ check_icmp_config check_icmp_config_init() {
34 34
35 .ttl = DEFAULT_TTL, 35 .ttl = DEFAULT_TTL,
36 .icmp_data_size = DEFAULT_PING_DATA_SIZE, 36 .icmp_data_size = DEFAULT_PING_DATA_SIZE,
37 .icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN,
38 .pkt_interval = DEFAULT_PKT_INTERVAL,
39 .target_interval = 0, 37 .target_interval = 0,
40 .number_of_packets = DEFAULT_NUMBER_OF_PACKETS, 38 .number_of_packets = DEFAULT_NUMBER_OF_PACKETS,
41 39
@@ -52,6 +50,8 @@ check_icmp_config check_icmp_config_init() {
52 50
53 .number_of_hosts = 0, 51 .number_of_hosts = 0,
54 .hosts = NULL, 52 .hosts = NULL,
53
54 .output_format_is_set = false,
55 }; 55 };
56 return tmp; 56 return tmp;
57} 57}
@@ -76,7 +76,7 @@ check_icmp_state check_icmp_state_init() {
76 76
77ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) { 77ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) {
78 ping_target_create_wrapper result = { 78 ping_target_create_wrapper result = {
79 .errorcode = OK, 79 .errorcode = 0,
80 }; 80 };
81 81
82 struct sockaddr_storage *tmp_addr = &address; 82 struct sockaddr_storage *tmp_addr = &address;
@@ -88,7 +88,7 @@ ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) {
88 ((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) || 88 ((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) ||
89 (tmp_addr->ss_family == AF_INET6 && 89 (tmp_addr->ss_family == AF_INET6 &&
90 (((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) { 90 (((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
91 result.errorcode = ERROR; 91 result.errorcode = 1;
92 return result; 92 return result;
93 } 93 }
94 94
diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h
index fc9dd5a6..be388d0a 100644
--- a/plugins-root/check_icmp.d/config.h
+++ b/plugins-root/check_icmp.d/config.h
@@ -12,11 +12,12 @@
12#include <arpa/inet.h> 12#include <arpa/inet.h>
13#include <stdint.h> 13#include <stdint.h>
14#include "./check_icmp_helpers.h" 14#include "./check_icmp_helpers.h"
15#include "output.h"
15 16
16/* threshold structure. all values are maximum allowed, exclusive */ 17/* threshold structure. all values are maximum allowed, exclusive */
17typedef struct { 18typedef struct {
18 unsigned char pl; /* max allowed packet loss in percent */ 19 unsigned char pl; /* max allowed packet loss in percent */
19 time_t rta; /* roundtrip time average, microseconds */ 20 time_t rta; /* roundtrip time average, microseconds */
20 double jitter; /* jitter time average, microseconds */ 21 double jitter; /* jitter time average, microseconds */
21 double mos; /* MOS */ 22 double mos; /* MOS */
22 double score; /* Score */ 23 double score; /* Score */
@@ -59,8 +60,6 @@ typedef struct {
59 60
60 unsigned long ttl; 61 unsigned long ttl;
61 unsigned short icmp_data_size; 62 unsigned short icmp_data_size;
62 unsigned short icmp_pkt_size;
63 time_t pkt_interval;
64 time_t target_interval; 63 time_t target_interval;
65 unsigned short number_of_packets; 64 unsigned short number_of_packets;
66 65
@@ -77,6 +76,9 @@ typedef struct {
77 76
78 unsigned short number_of_hosts; 77 unsigned short number_of_hosts;
79 check_icmp_target_container *hosts; 78 check_icmp_target_container *hosts;
79
80 mp_output_format output_format;
81 bool output_format_is_set;
80} check_icmp_config; 82} check_icmp_config;
81 83
82check_icmp_config check_icmp_config_init(); 84check_icmp_config check_icmp_config_init();
@@ -94,7 +96,9 @@ typedef struct icmp_ping_data {
94#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44) 96#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
95 97
96/* 80 msec packet interval by default */ 98/* 80 msec packet interval by default */
97#define DEFAULT_PKT_INTERVAL 80000 99// DEPRECATED, remove when removing the option
100#define DEFAULT_PKT_INTERVAL 80000
101
98#define DEFAULT_TARGET_INTERVAL 0 102#define DEFAULT_TARGET_INTERVAL 0
99 103
100#define DEFAULT_WARN_RTA 200000 104#define DEFAULT_WARN_RTA 200000
diff --git a/plugins-root/pst3.c b/plugins-root/pst3.c
index 1f69f3a6..1bfe3d35 100644
--- a/plugins-root/pst3.c
+++ b/plugins-root/pst3.c
@@ -1,45 +1,45 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* pst3 3 * pst3
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2008 Monitoring Plugins Development Team 6 * Copyright (c) 2008 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the pst3 executable. This is a replacement ps command 10 * This file contains the pst3 executable. This is a replacement ps command
11* for Solaris to get output which provides a long argument listing, which 11 * for Solaris to get output which provides a long argument listing, which
12* is not possible with the standard ps command (due to truncation). /usr/ucb/ps 12 * is not possible with the standard ps command (due to truncation). /usr/ucb/ps
13* also has issues where some fields run into each other. 13 * also has issues where some fields run into each other.
14* 14 *
15* This executable works by reading process address structures, so needs 15 * This executable works by reading process address structures, so needs
16* to be executed as root 16 * to be executed as root
17* 17 *
18* Originally written by R.W.Ingraham 18 * Originally written by R.W.Ingraham
19* Rewritten by Duncan Ferguson (Altinity Ltd, June 2008) 19 * Rewritten by Duncan Ferguson (Altinity Ltd, June 2008)
20* The rewrite was necessary as /dev/kmem is not available within 20 * The rewrite was necessary as /dev/kmem is not available within
21* non-global zones on Solaris 10 21 * non-global zones on Solaris 10
22* 22 *
23* Details for rewrite came from 23 * Details for rewrite came from
24* source of /usr/ucb/ps on Solaris: 24 * source of /usr/ucb/ps on Solaris:
25* http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff 25 * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff
26* usenet group posting 26 * usenet group posting
27* http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F 27 * http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F
28* 28 *
29* This program is free software: you can redistribute it and/or modify 29 * This program is free software: you can redistribute it and/or modify
30* it under the terms of the GNU General Public License as published by 30 * it under the terms of the GNU General Public License as published by
31* the Free Software Foundation, either version 3 of the License, or 31 * the Free Software Foundation, either version 3 of the License, or
32* (at your option) any later version. 32 * (at your option) any later version.
33* 33 *
34* This program is distributed in the hope that it will be useful, 34 * This program is distributed in the hope that it will be useful,
35* but WITHOUT ANY WARRANTY; without even the implied warranty of 35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37* GNU General Public License for more details. 37 * GNU General Public License for more details.
38* 38 *
39* You should have received a copy of the GNU General Public License 39 * You should have received a copy of the GNU General Public License
40* along with this program. If not, see <http://www.gnu.org/licenses/>. 40 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41* 41 *
42*****************************************************************************/ 42 *****************************************************************************/
43 43
44#include <stdio.h> 44#include <stdio.h>
45#include <stdlib.h> 45#include <stdlib.h>
@@ -55,14 +55,14 @@
55 * Constants 55 * Constants
56 */ 56 */
57 57
58#define PROC_DIR "/proc" 58#define PROC_DIR "/proc"
59#define ARGS 30 59#define ARGS 30
60 60
61/* 61/*
62 * Globals 62 * Globals
63 */ 63 */
64 64
65static char * szProg; 65static char *szProg;
66 66
67/* 67/*
68 * Prototypes 68 * Prototypes
@@ -71,192 +71,179 @@ void usage();
71 71
72/*----------------------------------------------------------------------------*/ 72/*----------------------------------------------------------------------------*/
73 73
74int main (int argc, char **argv) 74int main(int argc, char **argv) {
75{ 75 DIR *procdir;
76 DIR *procdir; 76 struct dirent *proc;
77 struct dirent *proc; 77 char ps_name[ARGS];
78 char ps_name[ARGS]; 78 char as_name[ARGS];
79 char as_name[ARGS]; 79 psinfo_t psinfo;
80 psinfo_t psinfo; 80
81 81 /* Set our program name global */
82 /* Set our program name global */ 82 if ((szProg = strrchr(argv[0], '/')) != NULL) {
83 if ((szProg = strrchr(argv[0], '/')) != NULL) 83 szProg++;
84 szProg++; 84 } else {
85 else 85 szProg = argv[0];
86 szProg = argv[0]; 86 }
87 87
88 /* if given any parameters, print out help */ 88 /* if given any parameters, print out help */
89 if(argc > 1) { 89 if (argc > 1) {
90 (void)usage(); 90 (void)usage();
91 exit(1); 91 exit(1);
92 } 92 }
93 93
94 /* Make sure that our euid is root */ 94 /* Make sure that our euid is root */
95 if (geteuid() != 0) 95 if (geteuid() != 0) {
96 { 96 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg);
97 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); 97 exit(1);
98 exit(1); 98 }
99 } 99
100 100 if ((procdir = opendir(PROC_DIR)) == NULL) {
101 if ((procdir = opendir(PROC_DIR)) == NULL) { 101 fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR);
102 fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR); 102 exit(1);
103 exit(1); 103 }
104 } 104
105 105 /* Display column headings */
106 /* Display column headings */ 106 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", 'S', "UID", "PID", "PPID", "VSZ", "RSS", "%CPU",
107 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", 107 "COMMAND", "ARGS");
108 'S', 108
109 "UID", 109 /* Zip through all of the process entries */
110 "PID", 110 while ((proc = readdir(procdir))) {
111 "PPID", 111 int ps_fd;
112 "VSZ", 112 int as_fd;
113 "RSS", 113 off_t argoff;
114 "%CPU", 114 int i;
115 "COMMAND", 115 char *args;
116 "ARGS" 116 char *procname;
117 ); 117 char *ptr;
118 118 int argslen;
119 /* Zip through all of the process entries */ 119 uintptr_t args_addr;
120 while((proc = readdir(procdir))) { 120 ;
121 int ps_fd; 121 uintptr_t *args_vecs;
122 int as_fd; 122 ;
123 off_t argoff; 123 int args_count;
124 int i; 124
125 char *args; 125 if (proc->d_name[0] == '.') {
126 char *procname; 126 continue;
127 char *ptr; 127 }
128 int argslen; 128
129 uintptr_t args_addr;; 129 sprintf(ps_name, "%s/%s/%s", PROC_DIR, proc->d_name, "psinfo");
130 uintptr_t *args_vecs;; 130 sprintf(as_name, "%s/%s/%s", PROC_DIR, proc->d_name, "as");
131 int args_count; 131 try_again:
132 132 if ((ps_fd = open(ps_name, O_RDONLY)) == -1) {
133 if(proc->d_name[0] == '.') 133 continue;
134 continue; 134 }
135 135
136 sprintf(ps_name,"%s/%s/%s",PROC_DIR,proc->d_name,"psinfo"); 136 if ((as_fd = open(as_name, O_RDONLY)) == -1) {
137 sprintf(as_name,"%s/%s/%s",PROC_DIR,proc->d_name,"as"); 137 close(ps_fd);
138try_again: 138 continue;
139 if((ps_fd = open(ps_name, O_RDONLY)) == -1) 139 }
140 continue; 140
141 141 if (read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
142 if((as_fd = open(as_name, O_RDONLY)) == -1) { 142 int err = errno;
143 close(ps_fd); 143 close(ps_fd);
144 continue; 144 close(as_fd);
145 } 145 if (err == EAGAIN) {
146 146 goto try_again;
147 if(read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { 147 }
148 int err = errno; 148 if (err != ENOENT) {
149 close(ps_fd); 149 fprintf(stderr, "%s: read() on %s: %s\n", szProg, ps_name, strerror(err));
150 close(as_fd); 150 }
151 if(err == EAGAIN) goto try_again; 151 continue;
152 if(err != ENOENT) 152 }
153 fprintf(stderr, "%s: read() on %s: %s\n", szProg, 153 close(ps_fd);
154 ps_name, strerror(err)); 154
155 continue; 155 /* system process, ignore since the previous version did */
156 } 156 if (psinfo.pr_nlwp == 0 || strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0) {
157 close(ps_fd); 157 continue;
158 158 }
159 /* system process, ignore since the previous version did */ 159
160 if( 160 /* get the procname to match previous versions */
161 psinfo.pr_nlwp == 0 || 161 procname = strdup(psinfo.pr_psargs);
162 strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 162 if ((ptr = strchr(procname, ' ')) != NULL) {
163 ) { 163 *ptr = '\0';
164 continue; 164 }
165 } 165 if ((ptr = strrchr(procname, '/')) != NULL) {
166 166 ptr++;
167 /* get the procname to match previous versions */ 167 } else {
168 procname = strdup(psinfo.pr_psargs); 168 ptr = procname;
169 if((ptr = strchr(procname, ' ')) != NULL) 169 }
170 *ptr = '\0'; 170
171 if((ptr = strrchr(procname, '/')) != NULL) 171 /*
172 ptr++; 172 * print out what we currently know
173 else 173 */
174 ptr = procname; 174 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", psinfo.pr_lwp.pr_sname, psinfo.pr_euid,
175 175 psinfo.pr_pid, psinfo.pr_ppid, psinfo.pr_size, psinfo.pr_rssize,
176 /* 176 ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), ptr);
177 * print out what we currently know 177 free(procname);
178 */ 178
179 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", 179 /*
180 psinfo.pr_lwp.pr_sname, 180 * and now for the command line stuff
181 psinfo.pr_euid, 181 */
182 psinfo.pr_pid, 182
183 psinfo.pr_ppid, 183 args_addr = psinfo.pr_argv;
184 psinfo.pr_size, 184 args_count = psinfo.pr_argc;
185 psinfo.pr_rssize, 185 args_vecs = malloc(args_count * sizeof(uintptr_t));
186 ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), 186
187 ptr 187 if (psinfo.pr_dmodel == PR_MODEL_NATIVE) {
188 ); 188 /* this process matches target process */
189 free(procname); 189 pread(as_fd, args_vecs, args_count * sizeof(uintptr_t), args_addr);
190 190 } else {
191 /* 191 /* this process is 64bit, target process is 32 bit*/
192 * and now for the command line stuff 192 caddr32_t *args_vecs32 = (caddr32_t *)args_vecs;
193 */ 193 pread(as_fd, args_vecs32, args_count * sizeof(caddr32_t), args_addr);
194 194 for (i = args_count - 1; i >= 0; --i) {
195 args_addr = psinfo.pr_argv; 195 args_vecs[i] = args_vecs32[i];
196 args_count = psinfo.pr_argc; 196 }
197 args_vecs = malloc(args_count * sizeof(uintptr_t)); 197 }
198 198
199 if(psinfo.pr_dmodel == PR_MODEL_NATIVE) { 199 /*
200 /* this process matches target process */ 200 * now read in the args - if what we read in fills buffer
201 pread(as_fd,args_vecs, args_count * sizeof(uintptr_t), 201 * resize buffer and reread that bit again
202 args_addr); 202 */
203 } else { 203 argslen = ARGS;
204 /* this process is 64bit, target process is 32 bit*/ 204 args = malloc(argslen + 1);
205 caddr32_t *args_vecs32 = (caddr32_t *)args_vecs; 205 for (i = 0; i < args_count; i++) {
206 pread(as_fd,args_vecs32,args_count * sizeof(caddr32_t), 206 memset(args, '\0', argslen + 1);
207 args_addr); 207 if (pread(as_fd, args, argslen, args_vecs[i]) <= 0) {
208 for (i=args_count-1;i>=0;--i) 208 break;
209 args_vecs[i]=args_vecs32[i]; 209 }
210 } 210 args[argslen] = '\0';
211 211 if (strlen(args) == argslen) {
212 /* 212 argslen += ARGS;
213 * now read in the args - if what we read in fills buffer 213 args = realloc(args, argslen + 1);
214 * resize buffer and reread that bit again 214 i--;
215 */ 215 continue;
216 argslen=ARGS; 216 }
217 args=malloc(argslen+1); 217 printf(" %s", args);
218 for(i=0;i<args_count;i++) { 218 }
219 memset(args,'\0',argslen+1); 219 free(args_vecs);
220 if(pread(as_fd, args, argslen, args_vecs[i]) <= 0) { 220 free(args);
221 break; 221 close(as_fd);
222 } 222 printf("\n");
223 args[argslen]='\0'; 223 }
224 if(strlen(args) == argslen){ 224
225 argslen += ARGS; 225 (void)closedir(procdir);
226 args = realloc(args, argslen + 1); 226
227 i--; 227 return (0);
228 continue;
229 }
230 printf(" %s", args);
231 }
232 free(args_vecs);
233 free(args);
234 close(as_fd);
235 printf("\n");
236 }
237
238 (void) closedir(procdir);
239
240 return (0);
241} 228}
242 229
243/*----------------------------------------------------------------------------*/ 230/*----------------------------------------------------------------------------*/
244 231
245void usage() { 232void usage() {
246 printf("%s: Help output\n\n", szProg); 233 printf("%s: Help output\n\n", szProg);
247 printf("If this program is given any arguments, this help is displayed.\n"); 234 printf("If this program is given any arguments, this help is displayed.\n");
248 printf("This command is used to print out the full command line for all\n"); 235 printf("This command is used to print out the full command line for all\n");
249 printf("running processes because /usr/bin/ps is limited to 80 chars and\n"); 236 printf("running processes because /usr/bin/ps is limited to 80 chars and\n");
250 printf("/usr/ucb/ps can merge columns together.\n\n"); 237 printf("/usr/ucb/ps can merge columns together.\n\n");
251 printf("Columns are:\n"); 238 printf("Columns are:\n");
252 printf("\tS - State of process - see 'ps' man page\n"); 239 printf("\tS - State of process - see 'ps' man page\n");
253 printf("\tUID - UID of the process owner\n"); 240 printf("\tUID - UID of the process owner\n");
254 printf("\tPID - PID of the process\n"); 241 printf("\tPID - PID of the process\n");
255 printf("\tPPID - PID of the parent process\n"); 242 printf("\tPPID - PID of the parent process\n");
256 printf("\tVSZ - Virtual memory usage (kilobytes)\n"); 243 printf("\tVSZ - Virtual memory usage (kilobytes)\n");
257 printf("\tRSS - Real memory usage (kilobytes)\n"); 244 printf("\tRSS - Real memory usage (kilobytes)\n");
258 printf("\t%%CPU - CPU usage\n"); 245 printf("\t%%CPU - CPU usage\n");
259 printf("\tCOMMAND - Command being run\n"); 246 printf("\tCOMMAND - Command being run\n");
260 printf("\tARGS - Full command line with arguments\n"); 247 printf("\tARGS - Full command line with arguments\n");
261 return; 248 return;
262} 249}
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};