├── Makefile ├── README.md ├── run_loop.sh └── src ├── Makefile └── dhcpdiscover.c /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2006-2013 OpenWrt.org 3 | # 4 | # This is free software, licensed under the GNU General Public License v2. 5 | # See /LICENSE for more information. 6 | # 7 | # Author: p4u 8 | 9 | include $(TOPDIR)/rules.mk 10 | 11 | PKG_NAME:=dhcpdiscover 12 | PKG_RELEASE:=1 13 | 14 | PKG_BUILD_DIR:=$(BUILD_DIR)/dhcpdiscover 15 | 16 | include $(INCLUDE_DIR)/package.mk 17 | include $(INCLUDE_DIR)/kernel.mk 18 | 19 | define Package/dhcpdiscover 20 | SECTION:=net 21 | CATEGORY:=Network 22 | TITLE:=dhcpdiscover 23 | endef 24 | 25 | define Package/dhcpdiscover/description 26 | Brings some information about the existing DHCP servers of the network 27 | endef 28 | 29 | define Build/Prepare 30 | mkdir -p $(PKG_BUILD_DIR) 31 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 32 | endef 33 | 34 | define Package/dhcpdiscover/install 35 | $(INSTALL_DIR) $(1)/bin 36 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/dhcpdiscover $(1)/bin/ 37 | endef 38 | 39 | $(eval $(call BuildPackage,dhcpdiscover)) 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | * Program: dhcpdiscover 2 | 3 | This program checks the existence and more details of a DHCP server 4 | 5 | * About the code structure 6 | 7 | The Makefile found in the directory of this README is for OpenWRT. It can be imported as a package. Inside the src/ directory the C code of dhcpdiscover can be found. If you want to compile it for your computer execute: cd src && make 8 | 9 | * Licence information 10 | 11 | Code under GPLv3 12 | 13 | Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org), 2013 OpenWRT.org 14 | 15 | * Contributors 16 | 17 | Mike Gore 25 Aug 2005: Modified for standalone operation 18 | Pau Escrich Jun 2013: Added -b option and ported to OpenWRT 19 | 20 | 21 | ___________________________________________________________ 22 | 23 | 24 | ``` 25 | Usage: dhcpdiscover [-s serverip] [-r requestedip] [-m clientmac ] [-b bannedip] [-t timeout] [-i interface] 26 | [-v] -s, --serverip=IPADDRESS 27 | IP address of DHCP server that we must hear from 28 | -r, --requestedip=IPADDRESS 29 | IP address that should be offered by at least one DHCP server 30 | -m, --mac=MACADDRESS 31 | Client MAC address to use for sending packets 32 | -b, --bannedip=IPADDRESS 33 | Server IP address to ignore 34 | -t, --timeout=INTEGER 35 | Seconds to wait for DHCPOFFER before timeout occurs 36 | -i, --interface=STRING 37 | Interface to to use for listening (i.e. eth0) 38 | -v, --verbose 39 | Print extra information (command-line use only) 40 | -p, --prometheus 41 | Print extra information in prometheus format 42 | -h, --help 43 | Print detailed help screen 44 | -V, --version 45 | Print version information 46 | 47 | Example: sudo ./dhcpdiscover -i eth0 -b 192.168.1.1 48 | ``` 49 | -------------------------------------------------------------------------------- /run_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | INTERFACES="wlan0 eth0" 4 | OUTPUT_PATH="./proms" 5 | LOOP_DELAY=60 6 | 7 | mkdir -p "$OUTPUT_PATH" 8 | 9 | while true; do 10 | for dev in $INTERFACES; do 11 | echo "checking $dev" 12 | ./dhcpdiscover -p -i "$dev" > "$OUTPUT_PATH/${dev}.prom" & 13 | done 14 | sleep "$LOOP_DELAY" 15 | done 16 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CPPFLAGS = 3 | CFLAGS = -Os -Wall 4 | LDFLAGS = 5 | CONFIGURE_ARGS = 6 | 7 | all: dhcpdiscover 8 | 9 | dhcpdiscover: 10 | $(CC) -o dhcpdiscover dhcpdiscover.c 11 | 12 | clean: 13 | rm -f dhcpdiscover 14 | -------------------------------------------------------------------------------- /src/dhcpdiscover.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Original name: CHECK_DHCP.C 4 | * Current name: DHCPDISCOVER.C 5 | * 6 | * License: GPL 7 | * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org) 8 | * Copyright (c) 2006-2013 OpenWRT.org 9 | * 10 | * License Information: 11 | * 12 | * This program is free software; you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation; either version 2 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License 23 | * along with this program; if not, write to the Free Software 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 | * 26 | *****************************************************************************/ 27 | 28 | const char* COPYRIGHT = " \ 29 | *\n \ 30 | * License: GPL\n \ 31 | * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n \ 32 | * Copyright (c) 2006-2013 OpenWRT.org \n \ 33 | * ====================================================== \n \ 34 | * Mike Gore 25 Aug 2005 \n \ 35 | * Modified for standalone operation \n \ 36 | * ====================================================== \n \ 37 | * Pau Escrich Jun 2013 \n \ 38 | * Added -b option and ported to OpenWRT \n \ 39 | * ====================================================== \n \ 40 | *\n \ 41 | ** License Information:\n \ 42 | *\n \ 43 | * This program is free software; you can redistribute it and/or modify\n \ 44 | * it under the terms of the GNU General Public License as published by\n \ 45 | * the Free Software Foundation; either version 2 of the License, or\n \ 46 | * (at your option) any later version.\n \ 47 | *\n \ 48 | * This program is distributed in the hope that it will be useful,\n \ 49 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\n \ 50 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n \ 51 | * GNU General Public License for more details.\n \ 52 | *\n \ 53 | * You should have received a copy of the GNU General Public License\n \ 54 | * along with this program; if not, write to the Free Software\n \ 55 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n \ 56 | *\n \ 57 | * $Id: dhcpdiscover.c,v 2$\n \ 58 | *"; 59 | 60 | const char* progname = "dhcpdiscover"; 61 | const char* revision = "$Revision: 2$"; 62 | const char* copyright = "2006-2013"; 63 | const char* email = "p4u@dabax.net"; 64 | 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | 83 | #if defined(__linux__) 84 | 85 | #include 86 | #include 87 | 88 | #elif defined(__bsd__) 89 | 90 | #include 91 | #include 92 | #include 93 | 94 | #elif defined(__sun__) || defined(__solaris__) || defined(__hpux__) 95 | 96 | #define INSAP 22 97 | #define OUTSAP 24 98 | 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | 105 | #define bcopy(source, destination, length) memcpy(destination, source, length) 106 | 107 | #define AREA_SZ 5000 /* buffer length in bytes */ 108 | static u_long ctl_area[AREA_SZ]; 109 | static u_long dat_area[AREA_SZ]; 110 | static struct strbuf ctl = { AREA_SZ, 0, (char*)ctl_area }; 111 | static struct strbuf dat = { AREA_SZ, 0, (char*)dat_area }; 112 | 113 | #define GOT_CTRL 1 114 | #define GOT_DATA 2 115 | #define GOT_BOTH 3 116 | #define GOT_INTR 4 117 | #define GOT_ERR 128 118 | 119 | #define u_int8_t uint8_t 120 | #define u_int16_t uint16_t 121 | #define u_int32_t uint32_t 122 | 123 | static int get_msg(int); 124 | static int check_ctrl(int); 125 | static int put_ctrl(int, int, int); 126 | static int put_both(int, int, int, int); 127 | static int dl_open(const char*, int, int*); 128 | static int dl_bind(int, int, u_char*); 129 | long mac_addr_dlpi(const char*, int, u_char*); 130 | 131 | #endif 132 | 133 | #define HAVE_GETOPT_H 134 | 135 | #define usage printf 136 | 137 | /**** Common definitions ****/ 138 | 139 | #define STATE_OK 0 140 | #define STATE_WARNING 1 141 | #define STATE_CRITICAL 2 142 | #define STATE_UNKNOWN -1 143 | 144 | #define OK 0 145 | #define ERROR -1 146 | 147 | #define FALSE 0 148 | #define TRUE 1 149 | 150 | /**** DHCP definitions ****/ 151 | 152 | #define MAX_DHCP_CHADDR_LENGTH 16 153 | #define MAX_DHCP_SNAME_LENGTH 64 154 | #define MAX_DHCP_FILE_LENGTH 128 155 | #define MAX_DHCP_OPTIONS_LENGTH 312 156 | 157 | typedef struct dhcp_packet_struct { 158 | u_int8_t op; /* packet type */ 159 | u_int8_t htype; /* type of hardware address for this machine (Ethernet, etc) */ 160 | u_int8_t hlen; /* length of hardware address (of this machine) */ 161 | u_int8_t hops; /* hops */ 162 | u_int32_t xid; /* random transaction id number - chosen by this machine */ 163 | u_int16_t secs; /* seconds used in timing */ 164 | u_int16_t flags; /* flags */ 165 | struct in_addr ciaddr; /* IP address of this machine (if we already have one) */ 166 | struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */ 167 | struct in_addr siaddr; /* IP address of DHCP server */ 168 | struct in_addr giaddr; /* IP address of DHCP relay */ 169 | unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */ 170 | char sname[MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */ 171 | char file[MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless 172 | booting?) */ 173 | char options[MAX_DHCP_OPTIONS_LENGTH]; /* options */ 174 | } dhcp_packet; 175 | 176 | typedef struct dhcp_offer_struct { 177 | struct in_addr server_address; /* address of DHCP server that sent this offer */ 178 | struct in_addr offered_address; /* the IP address that was offered to us */ 179 | u_int32_t lease_time; /* lease time in seconds */ 180 | u_int32_t renewal_time; /* renewal time in seconds */ 181 | u_int32_t rebinding_time; /* rebinding time in seconds */ 182 | struct dhcp_offer_struct* next; 183 | } dhcp_offer; 184 | 185 | typedef struct requested_server_struct { 186 | struct in_addr server_address; 187 | struct requested_server_struct* next; 188 | } requested_server; 189 | 190 | #define BOOTREQUEST 1 191 | #define BOOTREPLY 2 192 | 193 | #define DHCPDISCOVER 1 194 | #define DHCPOFFER 2 195 | #define DHCPREQUEST 3 196 | #define DHCPDECLINE 4 197 | #define DHCPACK 5 198 | #define DHCPNACK 6 199 | #define DHCPRELEASE 7 200 | 201 | #define DHCP_OPTION_MESSAGE_TYPE 53 202 | #define DHCP_OPTION_HOST_NAME 12 203 | #define DHCP_OPTION_BROADCAST_ADDRESS 28 204 | #define DHCP_OPTION_REQUESTED_ADDRESS 50 205 | #define DHCP_OPTION_LEASE_TIME 51 206 | #define DHCP_OPTION_RENEWAL_TIME 58 207 | #define DHCP_OPTION_REBINDING_TIME 59 208 | 209 | #define DHCP_INFINITE_TIME 0xFFFFFFFF 210 | 211 | #define DHCP_BROADCAST_FLAG 32768 212 | 213 | #define DHCP_SERVER_PORT 67 214 | #define DHCP_CLIENT_PORT 68 215 | 216 | #define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */ 217 | #define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */ 218 | 219 | unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = ""; 220 | unsigned int my_client_mac[MAX_DHCP_CHADDR_LENGTH]; 221 | int mymac = 0; 222 | 223 | struct in_addr banned_ip; 224 | int banned = 0; 225 | char baddr[16]; 226 | 227 | char network_interface_name[16] = "eth0"; 228 | 229 | u_int32_t packet_xid = 0; 230 | 231 | u_int32_t dhcp_lease_time = 0; 232 | u_int32_t dhcp_renewal_time = 0; 233 | u_int32_t dhcp_rebinding_time = 0; 234 | 235 | int dhcpoffer_timeout = 2; 236 | 237 | dhcp_offer* dhcp_offer_list = NULL; 238 | requested_server* requested_server_list = NULL; 239 | 240 | int valid_responses = 0; /* number of valid DHCPOFFERs we received */ 241 | int requested_servers = 0; 242 | int requested_responses = 0; 243 | 244 | int request_specific_address = FALSE; 245 | int received_requested_address = FALSE; 246 | int verbose = 0; 247 | int prometheus = 0; 248 | struct in_addr requested_address; 249 | 250 | void print_revision(const char* progname, const char* revision) { 251 | fprintf(stdout, "Program: %s %s\n", progname, revision); 252 | } 253 | 254 | int process_arguments(int, char**); 255 | int call_getopt(int, char**); 256 | int validate_arguments(void); 257 | void print_usage(void); 258 | void print_help(void); 259 | 260 | int get_hardware_address(int, char*); 261 | 262 | int send_dhcp_discover(int); 263 | int get_dhcp_offer(int); 264 | 265 | int get_results(void); 266 | 267 | int add_dhcp_offer(struct in_addr, dhcp_packet*); 268 | int free_dhcp_offer_list(void); 269 | int free_requested_server_list(void); 270 | 271 | int create_dhcp_socket(void); 272 | int close_dhcp_socket(int); 273 | int send_dhcp_packet(void*, int, int, struct sockaddr_in*); 274 | int receive_dhcp_packet(void*, int, int, int, struct sockaddr_in*); 275 | 276 | int main(int argc, char** argv) 277 | { 278 | int dhcp_socket; 279 | int result; 280 | 281 | setlocale(LC_ALL, ""); 282 | // bindtextdomain (PACKAGE, LOCALEDIR); 283 | // textdomain (PACKAGE); 284 | 285 | if (process_arguments(argc, argv) != OK) { 286 | printf("Could not parse arguments"); 287 | } 288 | 289 | // Set banned addr in string format in global var baddr 290 | if (banned) { 291 | inet_ntop(AF_INET, &(banned_ip), baddr, INET_ADDRSTRLEN); 292 | if (verbose) 293 | fprintf(stdout, "Banned addr:%s\n", baddr); 294 | } 295 | 296 | /* create socket for DHCP communications */ 297 | dhcp_socket = create_dhcp_socket(); 298 | 299 | /* get hardware address of client machine */ 300 | get_hardware_address(dhcp_socket, network_interface_name); 301 | 302 | /* send DHCPDISCOVER packet */ 303 | send_dhcp_discover(dhcp_socket); 304 | 305 | /* wait for a DHCPOFFER packet */ 306 | get_dhcp_offer(dhcp_socket); 307 | 308 | /* close socket we created */ 309 | close_dhcp_socket(dhcp_socket); 310 | 311 | /* determine state/plugin output to return */ 312 | if (!prometheus) { 313 | result = get_results(); 314 | } 315 | 316 | /* free allocated memory */ 317 | free_dhcp_offer_list(); 318 | free_requested_server_list(); 319 | 320 | return result; 321 | } 322 | 323 | /* determines hardware address on client machine */ 324 | int get_hardware_address(int sock, char* interface_name) 325 | { 326 | int i; 327 | 328 | #if defined(__linux__) 329 | struct ifreq ifr; 330 | 331 | strncpy((char*)&ifr.ifr_name, interface_name, sizeof(ifr.ifr_name)); 332 | 333 | // Added code to try to set local MAC address just to be through 334 | // If this fails the test will still work since 335 | // we do encode the MAC as part of the DHCP frame - tests show it works 336 | if (mymac) { 337 | int i; 338 | for (i = 0; i < MAX_DHCP_CHADDR_LENGTH; ++i) 339 | client_hardware_address[i] = my_client_mac[i]; 340 | memcpy(&ifr.ifr_hwaddr.sa_data, &client_hardware_address[0], 6); 341 | if (ioctl(sock, SIOCSIFHWADDR, &ifr) < 0) { 342 | fprintf(stderr, "Could not set hardware address of interface '%s'\n", interface_name); 343 | // perror("Error"); 344 | // exit(STATE_UNKNOWN); 345 | } 346 | } else { 347 | /* try and grab hardware address of requested interface */ 348 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { 349 | fprintf(stderr, "Could not get hardware address of interface '%s'\n", interface_name); 350 | exit(STATE_UNKNOWN); 351 | } 352 | memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, 6); 353 | } 354 | 355 | #elif defined(__bsd__) 356 | /* King 2004 see ACKNOWLEDGEMENTS */ 357 | 358 | int mib[6], len; 359 | char* buf; 360 | unsigned char* ptr; 361 | struct if_msghdr* ifm; 362 | struct sockaddr_dl* sdl; 363 | 364 | mib[0] = CTL_NET; 365 | mib[1] = AF_ROUTE; 366 | mib[2] = 0; 367 | mib[3] = AF_LINK; 368 | mib[4] = NET_RT_IFLIST; 369 | 370 | if ((mib[5] = if_nametoindex(interface_name)) == 0) { 371 | fprintf(stderr, "if_nametoindex error - %s.\n", strerror(errno); 372 | exit(STATE_UNKNOWN); 373 | } 374 | 375 | if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 376 | fprintf(stderr, "Couldn't get hardware address from %s. sysctl 1 error - %s.\n", interface_name, strerror(errno); 377 | exit(STATE_UNKNOWN); 378 | } 379 | 380 | if ((buf = malloc(len)) == NULL) { 381 | fprintf(stderr, "Couldn't get hardware address from interface %s. malloc error - %s.\n", interface_name, strerror(errno); 382 | exit(4); 383 | } 384 | 385 | if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 386 | fprintf(stderr, "Couldn't get hardware address from %s. sysctl 2 error - %s.\n", interface_name, strerror(errno); 387 | exit(STATE_UNKNOWN); 388 | } 389 | 390 | ifm = (struct if_msghdr*)buf; 391 | sdl = (struct sockaddr_dl*)(ifm + 1); 392 | ptr = (unsigned char*)LLADDR(sdl); 393 | memcpy(&client_hardware_address[0], ptr, 6); 394 | /* King 2004 */ 395 | 396 | #elif defined(__sun__) || defined(__solaris__) 397 | 398 | /* Kompf 2000-2003 see ACKNOWLEDGEMENTS */ 399 | long stat; 400 | char dev[20] = "/dev/"; 401 | char* p; 402 | int unit; 403 | 404 | for (p = interface_name; *p && isalpha(*p); p++) 405 | /* no-op */; 406 | if (p != '\0') { 407 | unit = atoi(p); 408 | *p = '\0'; 409 | strncat(dev, interface_name, 6); 410 | } else { 411 | fprintf(stderr, "can't find unit number in interface_name (%s) - expecting " 412 | "TypeNumber eg lnc0.\n", interface_name); 413 | exit(STATE_UNKNOWN); 414 | } 415 | stat = mac_addr_dlpi(dev, unit, client_hardware_address); 416 | if (stat != 0) { 417 | fprintf(stderr, "can't read MAC address from DLPI streams interface for " 418 | "device %s unit %d.\n", dev, unit); 419 | exit(STATE_UNKNOWN); 420 | } 421 | 422 | #elif defined(__hpux__) 423 | 424 | long stat; 425 | char dev[20] = "/dev/dlpi"; 426 | int unit = 0; 427 | 428 | stat = mac_addr_dlpi(dev, unit, client_hardware_address); 429 | if (stat != 0) { 430 | fprintf(stderr, "can't read MAC address from DLPI streams interface for " 431 | "device %s unit %d.\n", dev, unit); 432 | exit(STATE_UNKNOWN); 433 | } 434 | /* Kompf 2000-2003 */ 435 | 436 | #else 437 | fprintf(stderr, "can't get MAC address for this architecture.\n"); 438 | exit(STATE_UNKNOWN); 439 | #endif 440 | 441 | if (verbose) { 442 | fprintf(stdout, "Hardware address: "); 443 | for (i = 0; i < 6; ++i) 444 | fprintf(stdout, "%2.2x", client_hardware_address[i]); 445 | fprintf(stdout, "\n"); 446 | } 447 | 448 | return OK; 449 | } 450 | 451 | /* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 452 | int send_dhcp_discover(int sock) 453 | { 454 | dhcp_packet discover_packet; 455 | struct sockaddr_in sockaddr_broadcast; 456 | 457 | /* clear the packet data structure */ 458 | bzero(&discover_packet, sizeof(discover_packet)); 459 | 460 | /* boot request flag (backward compatible with BOOTP servers) */ 461 | discover_packet.op = BOOTREQUEST; 462 | 463 | /* hardware address type */ 464 | discover_packet.htype = ETHERNET_HARDWARE_ADDRESS; 465 | 466 | /* length of our hardware address */ 467 | discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH; 468 | 469 | discover_packet.hops = 0; 470 | 471 | /* transaction id is supposed to be random */ 472 | srand(time(NULL)); 473 | packet_xid = random(); 474 | discover_packet.xid = htonl(packet_xid); 475 | 476 | /**** WHAT THE HECK IS UP WITH THIS?!? IF I DON'T MAKE THIS CALL, ONLY ONE 477 | * SERVER RESPONSE IS PROCESSED!!!! ****/ 478 | /* downright bizzarre... */ 479 | ntohl(discover_packet.xid); 480 | 481 | /*discover_packet.secs=htons(65535);*/ 482 | discover_packet.secs = 0xFF; 483 | 484 | /* tell server it should broadcast its response */ 485 | discover_packet.flags = htons(DHCP_BROADCAST_FLAG); 486 | 487 | /* our hardware address */ 488 | memcpy(discover_packet.chaddr, client_hardware_address, ETHERNET_HARDWARE_ADDRESS_LENGTH); 489 | 490 | /* first four bytes of options field is magic cookie (as per RFC 2132) */ 491 | discover_packet.options[0] = '\x63'; 492 | discover_packet.options[1] = '\x82'; 493 | discover_packet.options[2] = '\x53'; 494 | discover_packet.options[3] = '\x63'; 495 | 496 | /* DHCP message type is embedded in options field */ 497 | discover_packet.options[4] = DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ 498 | discover_packet.options[5] = '\x01'; /* DHCP message option length in bytes */ 499 | discover_packet.options[6] = DHCPDISCOVER; 500 | 501 | /* the IP address we're requesting */ 502 | if (request_specific_address == TRUE) { 503 | discover_packet.options[7] = DHCP_OPTION_REQUESTED_ADDRESS; 504 | discover_packet.options[8] = '\x04'; 505 | memcpy(&discover_packet.options[9], &requested_address, sizeof(requested_address)); 506 | } 507 | 508 | /* send the DHCPDISCOVER packet to broadcast address */ 509 | sockaddr_broadcast.sin_family = AF_INET; 510 | sockaddr_broadcast.sin_port = htons(DHCP_SERVER_PORT); 511 | sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; 512 | bzero(&sockaddr_broadcast.sin_zero, sizeof(sockaddr_broadcast.sin_zero)); 513 | 514 | if (verbose) { 515 | fprintf(stdout, "DHCPDISCOVER to %s port %d\n", 516 | inet_ntoa(sockaddr_broadcast.sin_addr), 517 | ntohs(sockaddr_broadcast.sin_port)); 518 | fprintf(stdout, "DHCPDISCOVER XID: %lu (0x%X)\n", 519 | (unsigned long)ntohl(discover_packet.xid), 520 | ntohl(discover_packet.xid)); 521 | fprintf(stdout, "DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr)); 522 | fprintf(stdout, "DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr)); 523 | fprintf(stdout, "DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr)); 524 | fprintf(stdout, "DHCDISCOVER giaddr: %s\n", inet_ntoa(discover_packet.giaddr)); 525 | } 526 | 527 | /* send the DHCPDISCOVER packet out */ 528 | send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast); 529 | 530 | if (verbose) 531 | fprintf(stdout, "\n\n"); 532 | 533 | return OK; 534 | } 535 | 536 | /* waits for a DHCPOFFER message from one or more DHCP servers */ 537 | int get_dhcp_offer(int sock) 538 | { 539 | dhcp_packet offer_packet; 540 | struct sockaddr_in source; 541 | int result = OK; 542 | int responses = 0; 543 | int x; 544 | time_t start_time; 545 | time_t current_time; 546 | 547 | time(&start_time); 548 | 549 | /* receive as many responses as we can */ 550 | for (responses = 0, valid_responses = 0;;) { 551 | time(¤t_time); 552 | if ((current_time - start_time) >= dhcpoffer_timeout) 553 | break; 554 | 555 | if (verbose) 556 | fprintf(stdout, "\n\n"); 557 | 558 | bzero(&source, sizeof(source)); 559 | bzero(&offer_packet, sizeof(offer_packet)); 560 | 561 | result = OK; 562 | result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, 563 | dhcpoffer_timeout, &source); 564 | 565 | // checks if the source address is the banned one 566 | char saddr[16]; 567 | inet_ntop(AF_INET, &(source.sin_addr), saddr, INET_ADDRSTRLEN); 568 | 569 | if (banned && strcmp(saddr, baddr) == 0) { 570 | fprintf(stdout, "DHCP offer comming from the banned addr %s, ignoring it\n", 571 | baddr); 572 | result = 1; 573 | } 574 | 575 | if (result != OK) { 576 | if (verbose) 577 | fprintf(stdout, "Result=ERROR\n"); 578 | continue; 579 | } else { 580 | if (verbose) 581 | fprintf(stdout, "Result=OK\n"); 582 | responses++; 583 | } 584 | 585 | if (verbose) { 586 | fprintf(stdout, "DHCPOFFER from IP address %s\n", inet_ntoa(source.sin_addr)); 587 | fprintf(stdout, "DHCPOFFER XID: %lu (0x%X)\n", 588 | (unsigned long)ntohl(offer_packet.xid), ntohl(offer_packet.xid)); 589 | } 590 | 591 | /* check packet xid to see if its the same as the one we used in the 592 | * discover packet */ 593 | if (ntohl(offer_packet.xid) != packet_xid) { 594 | if (verbose) 595 | fprintf(stdout, "DHCPOFFER XID (%lu) did not match DHCPDISCOVER XID (%lu) - " 596 | "ignoring packet\n", 597 | (unsigned long)ntohl(offer_packet.xid), 598 | (unsigned long)packet_xid); 599 | continue; 600 | } 601 | 602 | /* check hardware address */ 603 | result = OK; 604 | if (verbose) 605 | fprintf(stdout, "DHCPOFFER chaddr: "); 606 | 607 | for (x = 0; x < ETHERNET_HARDWARE_ADDRESS_LENGTH; x++) { 608 | if (verbose) 609 | fprintf(stdout, "%02X", (unsigned char)offer_packet.chaddr[x]); 610 | 611 | if (offer_packet.chaddr[x] != client_hardware_address[x]) 612 | result = ERROR; 613 | } 614 | 615 | if (verbose) 616 | fprintf(stdout, "\n"); 617 | 618 | if (result == ERROR) { 619 | if (verbose) 620 | fprintf(stdout, "DHCPOFFER hardware address did not match our own - ignoring " 621 | "packet\n"); 622 | continue; 623 | } 624 | 625 | if (verbose) { 626 | fprintf(stdout, "DHCPOFFER ciaddr: %s\n", inet_ntoa(offer_packet.ciaddr)); 627 | fprintf(stdout, "DHCPOFFER yiaddr: %s\n", inet_ntoa(offer_packet.yiaddr)); 628 | fprintf(stdout, "DHCPOFFER siaddr: %s\n", inet_ntoa(offer_packet.siaddr)); 629 | fprintf(stdout, "DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr)); 630 | } 631 | 632 | add_dhcp_offer(source.sin_addr, &offer_packet); 633 | 634 | valid_responses++; 635 | } 636 | 637 | if (verbose) { 638 | fprintf(stdout, "Total responses seen on the wire: %d\n", responses); 639 | fprintf(stdout, "Valid responses for this machine: %d\n", valid_responses); 640 | } 641 | 642 | return OK; 643 | } 644 | 645 | /* sends a DHCP packet */ 646 | int send_dhcp_packet(void* buffer, int buffer_size, int sock, struct sockaddr_in* dest) 647 | { 648 | int result; 649 | 650 | result = sendto(sock, (char*)buffer, buffer_size, 0, (struct sockaddr*)dest, sizeof(*dest)); 651 | 652 | if (verbose) 653 | fprintf(stdout, "send_dhcp_packet result: %d\n", result); 654 | 655 | if (result < 0) 656 | return ERROR; 657 | 658 | return OK; 659 | } 660 | 661 | /* receives a DHCP packet */ 662 | int receive_dhcp_packet(void* buffer, int buffer_size, int sock, int timeout, struct sockaddr_in* address) 663 | { 664 | struct timeval tv; 665 | fd_set readfds; 666 | int recv_result; 667 | socklen_t address_size; 668 | struct sockaddr_in source_address; 669 | 670 | /* wait for data to arrive (up time timeout) */ 671 | tv.tv_sec = timeout; 672 | tv.tv_usec = 0; 673 | FD_ZERO(&readfds); 674 | FD_SET(sock, &readfds); 675 | select(sock + 1, &readfds, NULL, NULL, &tv); 676 | 677 | /* make sure some data has arrived */ 678 | if (!FD_ISSET(sock, &readfds)) { 679 | if (verbose) 680 | fprintf(stdout, "No (more) data received\n"); 681 | return ERROR; 682 | } 683 | else { 684 | /* why do we need to peek first? i don't know, its a hack. without it, the 685 | source address of the first packet received was not being interpreted 686 | correctly. sigh... */ 687 | bzero(&source_address, sizeof(source_address)); 688 | address_size = sizeof(source_address); 689 | recv_result = recvfrom(sock, (char*)buffer, buffer_size, MSG_PEEK, (struct sockaddr*)&source_address, &address_size); 690 | 691 | if (verbose) 692 | fprintf(stdout, "recv_result_1: %d\n", recv_result); 693 | 694 | recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0, 695 | (struct sockaddr *)&source_address, &address_size); 696 | if (verbose) 697 | fprintf(stdout, "recv_result_2: %d\n", recv_result); 698 | 699 | if (recv_result == -1) { 700 | if (verbose) { 701 | fprintf(stdout, "recvfrom() failed, "); 702 | fprintf(stdout, "errno: (%d) -> %s\n", errno, strerror(errno)); 703 | } 704 | return ERROR; 705 | } else { 706 | if (verbose) { 707 | fprintf(stdout, "receive_dhcp_packet() result: %d\n", recv_result); 708 | fprintf(stdout, "receive_dhcp_packet() source: %s\n", 709 | inet_ntoa(source_address.sin_addr)); 710 | } 711 | 712 | memcpy(address, &source_address, sizeof(source_address)); 713 | return OK; 714 | } 715 | } 716 | 717 | return OK; 718 | } 719 | 720 | /* creates a socket for DHCP communication */ 721 | int create_dhcp_socket(void) 722 | { 723 | struct sockaddr_in myname; 724 | struct ifreq interface; 725 | int sock; 726 | int flag = 1; 727 | 728 | /* Set up the address we're going to bind to. */ 729 | bzero(&myname, sizeof(myname)); 730 | myname.sin_family = AF_INET; 731 | myname.sin_port = htons(DHCP_CLIENT_PORT); 732 | myname.sin_addr.s_addr = INADDR_ANY; /* listen on any address */ 733 | bzero(&myname.sin_zero, sizeof(myname.sin_zero)); 734 | 735 | /* create a socket for DHCP communications */ 736 | sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 737 | if (sock < 0) { 738 | fprintf(stderr, "Could not create socket!\n"); 739 | exit(STATE_UNKNOWN); 740 | } 741 | 742 | if (verbose) 743 | fprintf(stdout, "DHCP socket: %d\n", sock); 744 | 745 | /* set the reuse address flag so we don't get errors when restarting */ 746 | flag = 1; 747 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) { 748 | fprintf(stderr, "Could not set reuse address option on DHCP socket!\n"); 749 | exit(STATE_UNKNOWN); 750 | } 751 | 752 | /* set the broadcast option - we need this to listen to DHCP broadcast 753 | * messages */ 754 | if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&flag, sizeof flag) < 0) { 755 | fprintf(stderr, "Could not set broadcast option on DHCP socket!\n"); 756 | exit(STATE_UNKNOWN); 757 | } 758 | 759 | /* bind socket to interface */ 760 | #if defined(__linux__) 761 | strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ); 762 | if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, 763 | sizeof(interface)) < 0) { 764 | fprintf(stderr, "Could not bind socket to interface %s. Check your " 765 | "privileges...\n", 766 | network_interface_name); 767 | exit(STATE_UNKNOWN); 768 | } 769 | #else 770 | strncpy(interface.ifr_name, network_interface_name, IFNAMSIZ); 771 | #endif 772 | 773 | /* bind the socket */ 774 | if (bind(sock, (struct sockaddr *)&myname, sizeof(myname)) < 0) { 775 | fprintf(stderr, "Could not bind to DHCP socket (port %d)! Check your " 776 | "privileges...\n", DHCP_CLIENT_PORT); 777 | exit(STATE_UNKNOWN); 778 | } 779 | 780 | return sock; 781 | } 782 | 783 | /* closes DHCP socket */ 784 | int close_dhcp_socket(int sock) 785 | { 786 | close(sock); 787 | return OK; 788 | } 789 | 790 | /* adds a requested server address to list in memory */ 791 | int add_requested_server(struct in_addr server_address) 792 | { 793 | requested_server* new_server; 794 | 795 | new_server = (requested_server*)malloc(sizeof(requested_server)); 796 | if (new_server == NULL) 797 | return ERROR; 798 | 799 | new_server->server_address = server_address; 800 | 801 | new_server->next = requested_server_list; 802 | requested_server_list = new_server; 803 | 804 | requested_servers++; 805 | 806 | if (verbose) 807 | fprintf(stdout, "Requested server address: %s\n", 808 | inet_ntoa(new_server->server_address)); 809 | 810 | return OK; 811 | } 812 | 813 | /* adds a DHCP OFFER to list in memory */ 814 | int add_dhcp_offer(struct in_addr source, dhcp_packet* offer_packet) 815 | { 816 | dhcp_offer* new_offer; 817 | int x; 818 | int y; 819 | unsigned option_type; 820 | unsigned option_length; 821 | 822 | if (offer_packet == NULL) 823 | return ERROR; 824 | 825 | /* process all DHCP options present in the packet */ 826 | for (x = 4; x < MAX_DHCP_OPTIONS_LENGTH;) { 827 | 828 | /* end of options (0 is really just a pad, but bail out anyway) */ 829 | if ((int)offer_packet->options[x] == -1 || (int)offer_packet->options[x] == 0) 830 | break; 831 | 832 | /* get option type */ 833 | option_type = offer_packet->options[x++]; 834 | 835 | /* get option length */ 836 | option_length = offer_packet->options[x++]; 837 | 838 | if (verbose) 839 | fprintf(stdout, "Option: %d (0x%02X)\n", option_type, option_length); 840 | 841 | /* get option data */ 842 | if (option_type == DHCP_OPTION_LEASE_TIME) { 843 | memcpy(&dhcp_lease_time, &offer_packet->options[x], sizeof(dhcp_lease_time)); 844 | dhcp_lease_time = ntohl(dhcp_lease_time); 845 | } 846 | if (option_type == DHCP_OPTION_RENEWAL_TIME) { 847 | memcpy(&dhcp_renewal_time, &offer_packet->options[x], sizeof(dhcp_renewal_time)); 848 | dhcp_renewal_time = ntohl(dhcp_renewal_time); 849 | } 850 | if (option_type == DHCP_OPTION_REBINDING_TIME) { 851 | memcpy(&dhcp_rebinding_time, &offer_packet->options[x], sizeof(dhcp_rebinding_time)); 852 | dhcp_rebinding_time = ntohl(dhcp_rebinding_time); 853 | } 854 | 855 | /* skip option data we're ignoring */ 856 | else 857 | for (y = 0; y < option_length; y++, x++); 858 | } 859 | 860 | if (verbose) { 861 | if (dhcp_lease_time == DHCP_INFINITE_TIME) 862 | fprintf(stdout, "Lease Time: Infinite\n"); 863 | else 864 | fprintf(stdout, "Lease Time: %lu seconds\n", (unsigned long)dhcp_lease_time); 865 | if (dhcp_renewal_time == DHCP_INFINITE_TIME) 866 | fprintf(stdout, "Renewal Time: Infinite\n"); 867 | else 868 | fprintf(stdout, "Renewal Time: %lu seconds\n", (unsigned long)dhcp_renewal_time); 869 | if (dhcp_rebinding_time == DHCP_INFINITE_TIME) 870 | fprintf(stdout, "Rebinding Time: Infinite\n"); 871 | fprintf(stdout, "Rebinding Time: %lu seconds\n", (unsigned long)dhcp_rebinding_time); 872 | } 873 | 874 | new_offer = (dhcp_offer*)malloc(sizeof(dhcp_offer)); 875 | 876 | if (new_offer == NULL) 877 | return ERROR; 878 | 879 | new_offer->server_address = source; 880 | new_offer->offered_address = offer_packet->yiaddr; 881 | new_offer->lease_time = dhcp_lease_time; 882 | new_offer->renewal_time = dhcp_renewal_time; 883 | new_offer->rebinding_time = dhcp_rebinding_time; 884 | 885 | if (verbose) { 886 | fprintf(stdout, "Added offer from server @ %s", 887 | inet_ntoa(new_offer->server_address)); 888 | fprintf(stdout, " of IP address %s\n", inet_ntoa(new_offer->offered_address)); 889 | } 890 | 891 | if (prometheus) { 892 | fprintf(stdout, "dhcpdiscover_offer{ "); 893 | fprintf(stdout, "server=\"%s\",", inet_ntoa(new_offer->server_address)); 894 | fprintf(stdout, "address=\"%s\",", inet_ntoa(new_offer->offered_address)); 895 | fprintf(stdout, "dev=\"%s\" } 1\n", network_interface_name); 896 | } 897 | 898 | /* add new offer to head of list */ 899 | new_offer->next = dhcp_offer_list; 900 | dhcp_offer_list = new_offer; 901 | 902 | return OK; 903 | } 904 | 905 | /* frees memory allocated to DHCP OFFER list */ 906 | int free_dhcp_offer_list(void) 907 | { 908 | dhcp_offer* this_offer; 909 | dhcp_offer* next_offer; 910 | 911 | for (this_offer = dhcp_offer_list; this_offer != NULL; this_offer = next_offer) { 912 | next_offer = this_offer->next; 913 | free(this_offer); 914 | } 915 | 916 | return OK; 917 | } 918 | 919 | /* frees memory allocated to requested server list */ 920 | int free_requested_server_list(void) 921 | { 922 | requested_server* this_server; 923 | requested_server* next_server; 924 | 925 | for (this_server = requested_server_list; this_server != NULL; this_server = next_server) { 926 | next_server = this_server->next; 927 | free(this_server); 928 | } 929 | 930 | return OK; 931 | } 932 | 933 | /* gets state and plugin output to return */ 934 | int get_results(void) 935 | { 936 | dhcp_offer* temp_offer; 937 | requested_server* temp_server; 938 | int result; 939 | u_int32_t max_lease_time = 0; 940 | 941 | received_requested_address = FALSE; 942 | 943 | /* checks responses from requested servers */ 944 | requested_responses = 0; 945 | if (requested_servers > 0) { 946 | 947 | for (temp_server = requested_server_list; temp_server != NULL; temp_server = temp_server->next) { 948 | 949 | for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 950 | 951 | /* get max lease time we were offered */ 952 | if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 953 | max_lease_time = temp_offer->lease_time; 954 | 955 | /* see if we got the address we requested */ 956 | if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 957 | received_requested_address = TRUE; 958 | 959 | /* see if the servers we wanted a response from talked to us or not */ 960 | if (!memcmp(&temp_offer->server_address, &temp_server->server_address, sizeof(temp_server->server_address))) { 961 | if (verbose) { 962 | fprintf(stdout, "DHCP Server Match: Offerer=%s", 963 | inet_ntoa(temp_offer->server_address)); 964 | fprintf(stdout, " Requested=%s\n", inet_ntoa(temp_server->server_address)); 965 | } 966 | requested_responses++; 967 | } 968 | } 969 | } 970 | } 971 | 972 | /* else check and see if we got our requested address from any server */ 973 | else { 974 | for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 975 | 976 | /* get max lease time we were offered */ 977 | if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 978 | max_lease_time = temp_offer->lease_time; 979 | 980 | /* see if we got the address we requested */ 981 | if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 982 | received_requested_address = TRUE; 983 | } 984 | } 985 | 986 | result = STATE_OK; 987 | if (valid_responses == 0) 988 | result = STATE_CRITICAL; 989 | else if (requested_servers > 0 && requested_responses == 0) 990 | result = STATE_CRITICAL; 991 | else if (requested_responses < requested_servers) 992 | result = STATE_WARNING; 993 | else if (request_specific_address == TRUE && received_requested_address == FALSE) 994 | result = STATE_WARNING; 995 | 996 | fprintf(stdout, "DHCP %s: ", (result == STATE_OK) ? "ok" : "problem"); 997 | 998 | /* we didn't receive any DHCPOFFERs */ 999 | if (dhcp_offer_list == NULL) { 1000 | fprintf(stdout, "No DHCPOFFERs were received.\n"); 1001 | return result; 1002 | } 1003 | 1004 | fprintf(stdout, "Received %d DHCPOFFER(s)", valid_responses); 1005 | 1006 | if (requested_servers > 0) 1007 | fprintf(stdout, ", %s%d of %d requested servers responded", 1008 | ((requested_responses < requested_servers) && requested_responses > 0) 1009 | ? "only " : "", 1010 | requested_responses, requested_servers); 1011 | 1012 | if (request_specific_address == TRUE) 1013 | fprintf(stdout, ", requested address (%s) was %soffered", 1014 | inet_ntoa(requested_address), 1015 | (received_requested_address == TRUE) ? "" : "not "); 1016 | 1017 | fprintf(stdout, ", max lease time = "); 1018 | if (max_lease_time == DHCP_INFINITE_TIME) 1019 | fprintf(stdout, "Infinity"); 1020 | else 1021 | fprintf(stdout, "%lu sec", (unsigned long)max_lease_time); 1022 | 1023 | fprintf(stdout, ".\n"); 1024 | 1025 | return result; 1026 | } 1027 | 1028 | /* process command-line arguments */ 1029 | int process_arguments(int argc, char** argv) 1030 | { 1031 | int c; 1032 | 1033 | if (argc < 1) 1034 | return ERROR; 1035 | 1036 | c = 0; 1037 | while ((c += (call_getopt(argc - c, &argv[c]))) < argc) { 1038 | /* 1039 | if(is_option(argv[c])) 1040 | continue; 1041 | */ 1042 | } 1043 | 1044 | return validate_arguments(); 1045 | } 1046 | 1047 | int call_getopt(int argc, char** argv) 1048 | { 1049 | int c = 0; 1050 | int i = 0; 1051 | struct in_addr ipaddress; 1052 | 1053 | #ifdef HAVE_GETOPT_H 1054 | int option_index = 0; 1055 | int ret; 1056 | static struct option long_options[] = { { "serverip", required_argument, 0, 's' }, { "requestedip", required_argument, 0, 'r' }, { "timeout", required_argument, 0, 't' }, { "interface", required_argument, 0, 'i' }, { "mac", required_argument, 0, 'm' }, { "bannedip", required_argument, 0, 'b' }, { "verbose", no_argument, 0, 'v' }, { "prometheus", no_argument, 0, 'p' }, { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; 1057 | #endif 1058 | 1059 | while (1) { 1060 | #ifdef HAVE_GETOPT_H 1061 | c = getopt_long(argc, argv, "+hVvpt:s:r:t:i:m:b:", long_options, &option_index); 1062 | #else 1063 | c = getopt(argc, argv, "+?hVvpt:s:r:t:i:m:b:"); 1064 | #endif 1065 | 1066 | i++; 1067 | 1068 | if (c == -1 || c == EOF || c == 1) 1069 | break; 1070 | 1071 | switch (c) { 1072 | case 'w': 1073 | case 'r': 1074 | case 't': 1075 | case 'i': 1076 | i++; 1077 | break; 1078 | default: 1079 | break; 1080 | } 1081 | 1082 | switch (c) { 1083 | 1084 | case 'm': /* Our MAC address */ 1085 | { 1086 | ret = sscanf(optarg, "%x:%x:%x:%x:%x:%x", my_client_mac + 0, my_client_mac + 1, my_client_mac + 2, my_client_mac + 3, my_client_mac + 4, my_client_mac + 5); 1087 | if (ret != 6) { 1088 | usage("Invalid MAC address\n"); 1089 | break; 1090 | } 1091 | for (i = 0; i < 6; ++i) 1092 | client_hardware_address[i] = my_client_mac[i]; 1093 | } 1094 | mymac = 1; 1095 | break; 1096 | case 'b': /* Banned IP */ 1097 | if (inet_aton(optarg, &ipaddress)) { 1098 | banned_ip = ipaddress; 1099 | banned = 1; 1100 | } else 1101 | fprintf(stdout, "Banned IP not specified, ignoring -b"); 1102 | break; 1103 | 1104 | case 's': /* DHCP server address */ 1105 | if (inet_aton(optarg, &ipaddress)) 1106 | add_requested_server(ipaddress); 1107 | /* 1108 | else 1109 | usage("Invalid server IP address\n"); 1110 | */ 1111 | break; 1112 | 1113 | case 'r': /* address we are requested from DHCP servers */ 1114 | if (inet_aton(optarg, &ipaddress)) { 1115 | requested_address = ipaddress; 1116 | request_specific_address = TRUE; 1117 | } 1118 | /* 1119 | else 1120 | usage("Invalid requested IP address\n"); 1121 | */ 1122 | break; 1123 | 1124 | case 't': /* timeout */ 1125 | /* 1126 | if(is_intnonneg(optarg)) 1127 | */ 1128 | if (atoi(optarg) > 0) 1129 | dhcpoffer_timeout = atoi(optarg); 1130 | /* 1131 | else 1132 | usage("Time interval must be a nonnegative integer\n"); 1133 | */ 1134 | break; 1135 | 1136 | case 'i': /* interface name */ 1137 | strncpy(network_interface_name, optarg, 1138 | sizeof(network_interface_name) - 1); 1139 | network_interface_name[sizeof(network_interface_name) - 1] = '\x0'; 1140 | break; 1141 | 1142 | case 'V': /* version */ 1143 | print_revision(progname, revision); 1144 | exit(STATE_OK); 1145 | 1146 | case 'h': /* help */ 1147 | print_help(); 1148 | exit(STATE_OK); 1149 | 1150 | case 'v': /* verbose */ 1151 | verbose = 1; 1152 | break; 1153 | 1154 | case 'p': /* prometheus */ 1155 | prometheus = 1; 1156 | break; 1157 | 1158 | default: /* help */ 1159 | fprintf(stdout, "Unknown argument: %s", optarg); 1160 | break; 1161 | } 1162 | } 1163 | 1164 | return i; 1165 | } 1166 | 1167 | int validate_arguments(void) { return OK; } 1168 | 1169 | #if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1170 | 1171 | /* Kompf 2000-2003 see ACKNOWLEDGEMENTS */ 1172 | 1173 | /* get a message from a stream; return type of message */ 1174 | static int get_msg(int fd) 1175 | { 1176 | int flags = 0; 1177 | int res, ret; 1178 | ctl_area[0] = 0; 1179 | dat_area[0] = 0; 1180 | ret = 0; 1181 | res = getmsg(fd, &ctl, &dat, &flags); 1182 | 1183 | if (res < 0) { 1184 | if (errno == EINTR) { 1185 | return (GOT_INTR); 1186 | } else { 1187 | fprintf(stdout, "%s\n", "get_msg FAILED."); 1188 | return (GOT_ERR); 1189 | } 1190 | } 1191 | if (ctl.len > 0) { 1192 | ret |= GOT_CTRL; 1193 | } 1194 | if (dat.len > 0) { 1195 | ret |= GOT_DATA; 1196 | } 1197 | return (ret); 1198 | } 1199 | 1200 | /* verify that dl_primitive in ctl_area = prim */ 1201 | static int check_ctrl(int prim) 1202 | { 1203 | dl_error_ack_t* err_ack = (dl_error_ack_t*)ctl_area; 1204 | if (err_ack->dl_primitive != prim) { 1205 | fprintf(stderr, "DLPI stream API failed to get MAC in check_ctrl: %s.\n", strerror(errno); 1206 | exit(STATE_UNKNOWN); 1207 | } 1208 | return 0; 1209 | } 1210 | 1211 | /* put a control message on a stream */ 1212 | static int put_ctrl(int fd, int len, int pri) 1213 | { 1214 | ctl.len = len; 1215 | if (putmsg(fd, &ctl, 0, pri) < 0) { 1216 | fprintf(stderr, "DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n", strerror(errno); 1217 | exit(STATE_UNKNOWN); 1218 | } 1219 | return 0; 1220 | } 1221 | 1222 | /* put a control + data message on a stream */ 1223 | static int put_both(int fd, int clen, int dlen, int pri) 1224 | { 1225 | ctl.len = clen; 1226 | dat.len = dlen; 1227 | if (putmsg(fd, &ctl, &dat, pri) < 0) { 1228 | fprintf(stderr, "DLPI stream API failed to get MAC in put_both/putmsg().\n", strerror(errno); 1229 | exit(STATE_UNKNOWN); 1230 | } 1231 | return 0; 1232 | } 1233 | 1234 | /* open file descriptor and attach */ 1235 | static int dl_open(const char* dev, int unit, int* fd) 1236 | { 1237 | dl_attach_req_t* attach_req = (dl_attach_req_t*)ctl_area; 1238 | if ((*fd = open(dev, O_RDWR)) == -1) { 1239 | fprintf(stderr, "DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n", dev, strerror(errno); 1240 | exit(STATE_UNKNOWN); 1241 | } 1242 | attach_req->dl_primitive = DL_ATTACH_REQ; 1243 | attach_req->dl_ppa = unit; 1244 | put_ctrl(*fd, sizeof(dl_attach_req_t), 0); 1245 | get_msg(*fd); 1246 | return check_ctrl(DL_OK_ACK); 1247 | } 1248 | 1249 | /* send DL_BIND_REQ */ 1250 | static int dl_bind(int fd, int sap, u_char* addr) 1251 | { 1252 | dl_bind_req_t* bind_req = (dl_bind_req_t*)ctl_area; 1253 | dl_bind_ack_t* bind_ack = (dl_bind_ack_t*)ctl_area; 1254 | bind_req->dl_primitive = DL_BIND_REQ; 1255 | bind_req->dl_sap = sap; 1256 | bind_req->dl_max_conind = 1; 1257 | bind_req->dl_service_mode = DL_CLDLS; 1258 | bind_req->dl_conn_mgmt = 0; 1259 | bind_req->dl_xidtest_flg = 0; 1260 | put_ctrl(fd, sizeof(dl_bind_req_t), 0); 1261 | get_msg(fd); 1262 | if (GOT_ERR == check_ctrl(DL_BIND_ACK)) { 1263 | fprintf(stderr, "DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n", strerror(errno); 1264 | exit(STATE_UNKNOWN); 1265 | } 1266 | bcopy((u_char*)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length); 1267 | return 0; 1268 | } 1269 | 1270 | /*********************************************************************** 1271 | * interface: 1272 | * function mac_addr_dlpi - get the mac address of the interface with 1273 | * type dev (eg lnc, hme) and unit (0, 1 ..) 1274 | * 1275 | * parameter: addr: an array of six bytes, has to be allocated by the caller 1276 | * 1277 | * return: 0 if OK, -1 if the address could not be determined 1278 | * 1279 | * 1280 | ***********************************************************************/ 1281 | 1282 | long mac_addr_dlpi(const char* dev, int unit, u_char* addr) 1283 | { 1284 | int fd; 1285 | u_char mac_addr[25]; 1286 | 1287 | if (GOT_ERR != dl_open(dev, unit, &fd)) { 1288 | if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) { 1289 | bcopy(mac_addr, addr, 6); 1290 | return 0; 1291 | } 1292 | } 1293 | close(fd); 1294 | return -1; 1295 | } 1296 | 1297 | /* Kompf 2000-2003 */ 1298 | 1299 | #endif 1300 | 1301 | /* print usage help */ 1302 | void print_help(void) 1303 | { 1304 | 1305 | print_revision(progname, revision); 1306 | 1307 | fprintf(stdout, COPYRIGHT, copyright, email); 1308 | 1309 | fprintf(stdout, "\n\nThis program checks the existence and more details of a DHCP " 1310 | "server\n\n"); 1311 | 1312 | print_usage(); 1313 | 1314 | fprintf(stdout, "\ 1315 | -s, --serverip=IPADDRESS\n\ 1316 | IP address of DHCP server that we must hear from\n\ 1317 | -r, --requestedip=IPADDRESS\n\ 1318 | IP address that should be offered by at least one DHCP server\n\ 1319 | -m, --mac=MACADDRESS\n\ 1320 | Client MAC address to use for sending packets\n\ 1321 | -b, --bannedip=IPADDRESS\n\ 1322 | Server IP address to ignore\n\ 1323 | -t, --timeout=INTEGER\n\ 1324 | Seconds to wait for DHCPOFFER before timeout occurs\n\ 1325 | -i, --interface=STRING\n\ 1326 | Interface to to use for listening (i.e. eth0)\n\ 1327 | -v, --verbose\n\ 1328 | Print extra information (command-line use only)\n\ 1329 | -p, --prometheus\n\ 1330 | Print extra information in prometheus format\n\ 1331 | -h, --help\n\ 1332 | Print detailed help screen\n\ 1333 | -V, --version\n\ 1334 | Print version information\n\n\ 1335 | Example: sudo ./dhcpdiscover -i eth0 -b 192.168.1.1\n\ 1336 | "); 1337 | } 1338 | 1339 | void print_usage(void) 1340 | { 1341 | fprintf(stdout, "\ 1342 | Usage: %s [-s serverip] [-r requestedip] [-m clientmac ] [-b bannedip] [-t timeout] [-i interface]\n\ 1343 | [-v] [-p]", progname); 1344 | } 1345 | --------------------------------------------------------------------------------