summaryrefslogtreecommitdiffstats
path: root/plugins-root/check_dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root/check_dhcp.c')
-rw-r--r--plugins-root/check_dhcp.c1021
1 files changed, 599 insertions, 422 deletions
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}