diff options
| author | Stanley Hopcroft <stanleyhopcroft@users.sourceforge.net> | 2004-12-07 02:33:17 +0000 |
|---|---|---|
| committer | Stanley Hopcroft <stanleyhopcroft@users.sourceforge.net> | 2004-12-07 02:33:17 +0000 |
| commit | d50a9917ef38c44ac2067dba508cf2e690ff1412 (patch) | |
| tree | ce8f21a473e9339ae1424418ad31cdc483c0f462 /plugins | |
| parent | 8ce197c306c62402aa20ea6d821462062bd1843e (diff) | |
| download | monitoring-plugins-d50a9917ef38c44ac2067dba508cf2e690ff1412.tar.gz | |
New plugin: check_dhcp.c. Attempt to port to non Linux platform.
git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1008 f882894a-f735-0410-b71e-b25c423dba1c
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/Makefile.am | 8 | ||||
| -rw-r--r-- | plugins/check_dhcp.c | 1061 |
2 files changed, 1066 insertions, 3 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index b87154d0..33f7686a 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am | |||
| @@ -10,7 +10,7 @@ localedir = $(datadir)/locale | |||
| 10 | DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ | 10 | DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ |
| 11 | LIBS = @LIBINTL@ @LIBS@ | 11 | LIBS = @LIBINTL@ @LIBS@ |
| 12 | 12 | ||
| 13 | libexec_PROGRAMS = check_disk check_dummy check_http check_load \ | 13 | libexec_PROGRAMS = check_dhcp check_disk check_dummy check_http check_load \ |
| 14 | check_mrtg check_mrtgtraf check_nwstat check_overcr check_ping \ | 14 | check_mrtg check_mrtgtraf check_nwstat check_overcr check_ping \ |
| 15 | check_real check_smtp check_ssh check_tcp check_time \ | 15 | check_real check_smtp check_ssh check_tcp check_time \ |
| 16 | check_udp check_ups check_users negate urlize check_icmp \ | 16 | check_udp check_ups check_users negate urlize check_icmp \ |
| @@ -44,6 +44,7 @@ AM_INSTALL_PROGRAM_FLAGS = @INSTALL_OPTS@ | |||
| 44 | ############################################################################## | 44 | ############################################################################## |
| 45 | # the actual targets | 45 | # the actual targets |
| 46 | 46 | ||
| 47 | check_dhcp_LDADD = $(BASEOBJS) | ||
| 47 | check_dig_LDADD = $(NETLIBS) popen.o | 48 | check_dig_LDADD = $(NETLIBS) popen.o |
| 48 | check_disk_LDADD = $(BASEOBJS) popen.o | 49 | check_disk_LDADD = $(BASEOBJS) popen.o |
| 49 | check_dns_LDADD = $(NETLIBS) popen.o | 50 | check_dns_LDADD = $(NETLIBS) popen.o |
| @@ -80,6 +81,7 @@ check_ide_smart_LDADD = $(BASEOBJS) | |||
| 80 | negate_LDADD = $(BASEOBJS) popen.o | 81 | negate_LDADD = $(BASEOBJS) popen.o |
| 81 | urlize_LDADD = $(BASEOBJS) popen.o | 82 | urlize_LDADD = $(BASEOBJS) popen.o |
| 82 | 83 | ||
| 84 | check_dhcp_DEPENDENCIES = check_dhcp.c $(DEPLIBS) | ||
| 83 | check_dig_DEPENDENCIES = check_dig.c $(NETOBJS) popen.o $(DEPLIBS) | 85 | check_dig_DEPENDENCIES = check_dig.c $(NETOBJS) popen.o $(DEPLIBS) |
| 84 | check_disk_DEPENDENCIES = check_disk.c $(BASEOBJS) popen.o $(DEPLIBS) | 86 | check_disk_DEPENDENCIES = check_disk.c $(BASEOBJS) popen.o $(DEPLIBS) |
| 85 | check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) popen.o $(DEPLIBS) | 87 | check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) popen.o $(DEPLIBS) |
| @@ -88,6 +90,8 @@ check_fping_DEPENDENCIES = check_fping.c $(NETOBJS) popen.o $(DEPLIBS) | |||
| 88 | check_game_DEPENDENCIES = check_game.c $(DEPLIBS) | 90 | check_game_DEPENDENCIES = check_game.c $(DEPLIBS) |
| 89 | check_http_DEPENDENCIES = check_http.c $(NETOBJS) $(DEPLIBS) | 91 | check_http_DEPENDENCIES = check_http.c $(NETOBJS) $(DEPLIBS) |
| 90 | check_hpjd_DEPENDENCIES = check_hpjd.c $(NETOBJS) popen.o $(DEPLIBS) | 92 | check_hpjd_DEPENDENCIES = check_hpjd.c $(NETOBJS) popen.o $(DEPLIBS) |
| 93 | check_icmp_DEPENDENCIES = check_icmp.c $(DEPLIBS) | ||
| 94 | check_ide_smart_DEPENDENCIES = check_ide_smart.c $(BASEOBJS) $(DEPLIBS) | ||
| 91 | check_ldap_DEPENDENCIES = check_ldap.c $(NETOBJS) $(DEPLIBS) | 95 | check_ldap_DEPENDENCIES = check_ldap.c $(NETOBJS) $(DEPLIBS) |
| 92 | check_load_DEPENDENCIES = check_load.c $(BASEOBJS) popen.o $(DEPLIBS) | 96 | check_load_DEPENDENCIES = check_load.c $(BASEOBJS) popen.o $(DEPLIBS) |
| 93 | check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS) | 97 | check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS) |
| @@ -112,10 +116,8 @@ check_udp_DEPENDENCIES = check_udp.c $(NETOBJS) $(DEPLIBS) | |||
| 112 | check_ups_DEPENDENCIES = check_ups.c $(NETOBJS) $(DEPLIBS) | 116 | check_ups_DEPENDENCIES = check_ups.c $(NETOBJS) $(DEPLIBS) |
| 113 | check_users_DEPENDENCIES = check_users.c $(BASEOBJS) popen.o $(DEPLIBS) | 117 | check_users_DEPENDENCIES = check_users.c $(BASEOBJS) popen.o $(DEPLIBS) |
| 114 | check_by_ssh_DEPENDENCIES = check_by_ssh.c $(NETOBJS) popen.o $(DEPLIBS) | 118 | check_by_ssh_DEPENDENCIES = check_by_ssh.c $(NETOBJS) popen.o $(DEPLIBS) |
| 115 | check_ide_smart_DEPENDENCIES = check_ide_smart.c $(BASEOBJS) $(DEPLIBS) | ||
| 116 | negate_DEPENDENCIES = negate.c $(BASEOBJS) popen.o $(DEPLIBS) | 119 | negate_DEPENDENCIES = negate.c $(BASEOBJS) popen.o $(DEPLIBS) |
| 117 | urlize_DEPENDENCIES = urlize.c $(BASEOBJS) popen.o $(DEPLIBS) | 120 | urlize_DEPENDENCIES = urlize.c $(BASEOBJS) popen.o $(DEPLIBS) |
| 118 | check_icmp_DEPENDENCIES = check_icmp.c $(DEPLIBS) | ||
| 119 | 121 | ||
| 120 | ############################################################################## | 122 | ############################################################################## |
| 121 | # secondary dependencies | 123 | # secondary dependencies |
diff --git a/plugins/check_dhcp.c b/plugins/check_dhcp.c new file mode 100644 index 00000000..ee893cd2 --- /dev/null +++ b/plugins/check_dhcp.c | |||
| @@ -0,0 +1,1061 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * | ||
| 3 | * CHECK_DHCP.C | ||
| 4 | * | ||
| 5 | * Program: DHCP plugin for Nagios | ||
| 6 | * License: GPL | ||
| 7 | * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org) | ||
| 8 | * | ||
| 9 | * License Information: | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with this program; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | * | ||
| 25 | *****************************************************************************/ | ||
| 26 | |||
| 27 | #include "common.h" | ||
| 28 | #include "netutils.h" | ||
| 29 | #include "utils.h" | ||
| 30 | |||
| 31 | #include <stdio.h> | ||
| 32 | #include <stdlib.h> | ||
| 33 | #include <string.h> | ||
| 34 | #include <errno.h> | ||
| 35 | #include <unistd.h> | ||
| 36 | #include <sys/time.h> | ||
| 37 | #include <sys/ioctl.h> | ||
| 38 | #include <fcntl.h> | ||
| 39 | #include <getopt.h> | ||
| 40 | #include <sys/socket.h> | ||
| 41 | #include <sys/types.h> | ||
| 42 | #include <netdb.h> | ||
| 43 | #include <netinet/in.h> | ||
| 44 | #include <net/if.h> | ||
| 45 | #include <arpa/inet.h> | ||
| 46 | |||
| 47 | #if defined( __linux__ ) | ||
| 48 | #include <linux/if_ether.h> | ||
| 49 | #include <features.h> | ||
| 50 | #else | ||
| 51 | #include <netinet/if_ether.h> | ||
| 52 | #include <sys/sysctl.h> | ||
| 53 | #include <net/if_dl.h> | ||
| 54 | #endif | ||
| 55 | |||
| 56 | const char *progname = "check_dhcp"; | ||
| 57 | |||
| 58 | /*#define DEBUG*/ | ||
| 59 | #define HAVE_GETOPT_H | ||
| 60 | |||
| 61 | |||
| 62 | /**** Common definitions ****/ | ||
| 63 | |||
| 64 | #define STATE_OK 0 | ||
| 65 | #define STATE_WARNING 1 | ||
| 66 | #define STATE_CRITICAL 2 | ||
| 67 | #define STATE_UNKNOWN -1 | ||
| 68 | |||
| 69 | #define OK 0 | ||
| 70 | #define ERROR -1 | ||
| 71 | |||
| 72 | #define FALSE 0 | ||
| 73 | #define TRUE 1 | ||
| 74 | |||
| 75 | |||
| 76 | /**** DHCP definitions ****/ | ||
| 77 | |||
| 78 | #define MAX_DHCP_CHADDR_LENGTH 16 | ||
| 79 | #define MAX_DHCP_SNAME_LENGTH 64 | ||
| 80 | #define MAX_DHCP_FILE_LENGTH 128 | ||
| 81 | #define MAX_DHCP_OPTIONS_LENGTH 312 | ||
| 82 | |||
| 83 | |||
| 84 | typedef struct dhcp_packet_struct{ | ||
| 85 | u_int8_t op; /* packet type */ | ||
| 86 | u_int8_t htype; /* type of hardware address for this machine (Ethernet, etc) */ | ||
| 87 | u_int8_t hlen; /* length of hardware address (of this machine) */ | ||
| 88 | u_int8_t hops; /* hops */ | ||
| 89 | u_int32_t xid; /* random transaction id number - chosen by this machine */ | ||
| 90 | u_int16_t secs; /* seconds used in timing */ | ||
| 91 | u_int16_t flags; /* flags */ | ||
| 92 | struct in_addr ciaddr; /* IP address of this machine (if we already have one) */ | ||
| 93 | struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */ | ||
| 94 | struct in_addr siaddr; /* IP address of DHCP server */ | ||
| 95 | struct in_addr giaddr; /* IP address of DHCP relay */ | ||
| 96 | unsigned char chaddr [MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */ | ||
| 97 | char sname [MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */ | ||
| 98 | char file [MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */ | ||
| 99 | char options[MAX_DHCP_OPTIONS_LENGTH]; /* options */ | ||
| 100 | }dhcp_packet; | ||
| 101 | |||
| 102 | |||
| 103 | typedef struct dhcp_offer_struct{ | ||
| 104 | struct in_addr server_address; /* address of DHCP server that sent this offer */ | ||
| 105 | struct in_addr offered_address; /* the IP address that was offered to us */ | ||
| 106 | u_int32_t lease_time; /* lease time in seconds */ | ||
| 107 | u_int32_t renewal_time; /* renewal time in seconds */ | ||
| 108 | u_int32_t rebinding_time; /* rebinding time in seconds */ | ||
| 109 | struct dhcp_offer_struct *next; | ||
| 110 | }dhcp_offer; | ||
| 111 | |||
| 112 | |||
| 113 | typedef struct requested_server_struct{ | ||
| 114 | struct in_addr server_address; | ||
| 115 | struct requested_server_struct *next; | ||
| 116 | }requested_server; | ||
| 117 | |||
| 118 | |||
| 119 | #define BOOTREQUEST 1 | ||
| 120 | #define BOOTREPLY 2 | ||
| 121 | |||
| 122 | #define DHCPDISCOVER 1 | ||
| 123 | #define DHCPOFFER 2 | ||
| 124 | #define DHCPREQUEST 3 | ||
| 125 | #define DHCPDECLINE 4 | ||
| 126 | #define DHCPACK 5 | ||
| 127 | #define DHCPNACK 6 | ||
| 128 | #define DHCPRELEASE 7 | ||
| 129 | |||
| 130 | #define DHCP_OPTION_MESSAGE_TYPE 53 | ||
| 131 | #define DHCP_OPTION_HOST_NAME 12 | ||
| 132 | #define DHCP_OPTION_BROADCAST_ADDRESS 28 | ||
| 133 | #define DHCP_OPTION_REQUESTED_ADDRESS 50 | ||
| 134 | #define DHCP_OPTION_LEASE_TIME 51 | ||
| 135 | #define DHCP_OPTION_RENEWAL_TIME 58 | ||
| 136 | #define DHCP_OPTION_REBINDING_TIME 59 | ||
| 137 | |||
| 138 | #define DHCP_INFINITE_TIME 0xFFFFFFFF | ||
| 139 | |||
| 140 | #define DHCP_BROADCAST_FLAG 32768 | ||
| 141 | |||
| 142 | #define DHCP_SERVER_PORT 67 | ||
| 143 | #define DHCP_CLIENT_PORT 68 | ||
| 144 | |||
| 145 | #define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */ | ||
| 146 | #define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */ | ||
| 147 | |||
| 148 | unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]=""; | ||
| 149 | |||
| 150 | char network_interface_name[8]="eth0"; | ||
| 151 | |||
| 152 | u_int32_t packet_xid=0; | ||
| 153 | |||
| 154 | u_int32_t dhcp_lease_time=0; | ||
| 155 | u_int32_t dhcp_renewal_time=0; | ||
| 156 | u_int32_t dhcp_rebinding_time=0; | ||
| 157 | |||
| 158 | int dhcpoffer_timeout=2; | ||
| 159 | |||
| 160 | dhcp_offer *dhcp_offer_list=NULL; | ||
| 161 | requested_server *requested_server_list=NULL; | ||
| 162 | |||
| 163 | int valid_responses=0; /* number of valid DHCPOFFERs we received */ | ||
| 164 | int requested_servers=0; | ||
| 165 | int requested_responses=0; | ||
| 166 | |||
| 167 | int request_specific_address=FALSE; | ||
| 168 | int received_requested_address=FALSE; | ||
| 169 | struct in_addr requested_address; | ||
| 170 | |||
| 171 | |||
| 172 | int process_arguments(int, char **); | ||
| 173 | int call_getopt(int, char **); | ||
| 174 | int validate_arguments(void); | ||
| 175 | void print_usage(void); | ||
| 176 | void print_help(void); | ||
| 177 | |||
| 178 | int get_hardware_address(int,char *); | ||
| 179 | |||
| 180 | int send_dhcp_discover(int); | ||
| 181 | int get_dhcp_offer(int); | ||
| 182 | |||
| 183 | int get_results(void); | ||
| 184 | |||
| 185 | int add_dhcp_offer(struct in_addr,dhcp_packet *); | ||
| 186 | int free_dhcp_offer_list(void); | ||
| 187 | int free_requested_server_list(void); | ||
| 188 | |||
| 189 | int create_dhcp_socket(void); | ||
| 190 | int close_dhcp_socket(int); | ||
| 191 | int send_dhcp_packet(void *,int,int,struct sockaddr_in *); | ||
| 192 | int receive_dhcp_packet(void *,int,int,int,struct sockaddr_in *); | ||
| 193 | |||
| 194 | |||
| 195 | |||
| 196 | int main(int argc, char **argv){ | ||
| 197 | int dhcp_socket; | ||
| 198 | int result; | ||
| 199 | |||
| 200 | if(process_arguments(argc,argv)!=OK){ | ||
| 201 | /*usage("Invalid command arguments supplied\n");*/ | ||
| 202 | printf("Invalid command arguments supplied\n"); | ||
| 203 | exit(STATE_UNKNOWN); | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | /* create socket for DHCP communications */ | ||
| 208 | dhcp_socket=create_dhcp_socket(); | ||
| 209 | |||
| 210 | /* get hardware address of client machine */ | ||
| 211 | get_hardware_address(dhcp_socket,network_interface_name); | ||
| 212 | |||
| 213 | /* send DHCPDISCOVER packet */ | ||
| 214 | send_dhcp_discover(dhcp_socket); | ||
| 215 | |||
| 216 | /* wait for a DHCPOFFER packet */ | ||
| 217 | get_dhcp_offer(dhcp_socket); | ||
| 218 | |||
| 219 | /* close socket we created */ | ||
| 220 | close_dhcp_socket(dhcp_socket); | ||
| 221 | |||
| 222 | /* determine state/plugin output to return */ | ||
| 223 | result=get_results(); | ||
| 224 | |||
| 225 | /* free allocated memory */ | ||
| 226 | free_dhcp_offer_list(); | ||
| 227 | free_requested_server_list(); | ||
| 228 | |||
| 229 | return result; | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | |||
| 234 | /* determines hardware address on client machine */ | ||
| 235 | int get_hardware_address(int sock,char *interface_name){ | ||
| 236 | #if defined(__linux__) | ||
| 237 | struct ifreq ifr; | ||
| 238 | |||
| 239 | strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)); | ||
| 240 | |||
| 241 | /* try and grab hardware address of requested interface */ | ||
| 242 | if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0){ | ||
| 243 | printf("Error: Could not get hardware address of interface '%s'\n",interface_name); | ||
| 244 | exit(STATE_UNKNOWN); | ||
| 245 | } | ||
| 246 | |||
| 247 | memcpy(&client_hardware_address[0],&ifr.ifr_hwaddr.sa_data,6); | ||
| 248 | #else | ||
| 249 | /* Code from getmac.c posted at http://lists.freebsd.org/pipermail/freebsd-hackers/2004-June/007415.html | ||
| 250 | * by Alecs King based on Unix Network programming Ch 17 | ||
| 251 | */ | ||
| 252 | |||
| 253 | int mib[6], len; | ||
| 254 | char *buf; | ||
| 255 | unsigned char *ptr; | ||
| 256 | struct if_msghdr *ifm; | ||
| 257 | struct sockaddr_dl *sdl; | ||
| 258 | |||
| 259 | mib[0] = CTL_NET; | ||
| 260 | mib[1] = AF_ROUTE; | ||
| 261 | mib[2] = 0; | ||
| 262 | mib[3] = AF_LINK; | ||
| 263 | mib[4] = NET_RT_IFLIST; | ||
| 264 | |||
| 265 | if ((mib[5] = if_nametoindex(interface_name)) == 0) { | ||
| 266 | perror("if_nametoindex error"); | ||
| 267 | exit(2); | ||
| 268 | } | ||
| 269 | |||
| 270 | if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { | ||
| 271 | perror("sysctl 1 error"); | ||
| 272 | exit(3); | ||
| 273 | } | ||
| 274 | |||
| 275 | if ((buf = malloc(len)) == NULL) { | ||
| 276 | perror("malloc error"); | ||
| 277 | exit(4); | ||
| 278 | } | ||
| 279 | |||
| 280 | if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { | ||
| 281 | perror("sysctl 2 error"); | ||
| 282 | exit(5); | ||
| 283 | } | ||
| 284 | |||
| 285 | ifm = (struct if_msghdr *)buf; | ||
| 286 | sdl = (struct sockaddr_dl *)(ifm + 1); | ||
| 287 | ptr = (unsigned char *)LLADDR(sdl); | ||
| 288 | memcpy(&client_hardware_address[0], ptr, 6) ; | ||
| 289 | #endif | ||
| 290 | |||
| 291 | |||
| 292 | #ifdef DEBUG | ||
| 293 | printf("Hardware address: %02x:%02x:%02x:",client_hardware_address[0],client_hardware_address[1],client_hardware_address[2]); | ||
| 294 | printf("%02x:",client_hardware_address[3]); | ||
| 295 | printf("%02x:%02x\n",client_hardware_address[4],client_hardware_address[5]); | ||
| 296 | printf("\n"); | ||
| 297 | #endif | ||
| 298 | |||
| 299 | return OK; | ||
| 300 | } | ||
| 301 | |||
| 302 | |||
| 303 | /* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ | ||
| 304 | int send_dhcp_discover(int sock){ | ||
| 305 | dhcp_packet discover_packet; | ||
| 306 | struct sockaddr_in sockaddr_broadcast; | ||
| 307 | |||
| 308 | |||
| 309 | /* clear the packet data structure */ | ||
| 310 | bzero(&discover_packet,sizeof(discover_packet)); | ||
| 311 | |||
| 312 | |||
| 313 | /* boot request flag (backward compatible with BOOTP servers) */ | ||
| 314 | discover_packet.op=BOOTREQUEST; | ||
| 315 | |||
| 316 | /* hardware address type */ | ||
| 317 | discover_packet.htype=ETHERNET_HARDWARE_ADDRESS; | ||
| 318 | |||
| 319 | /* length of our hardware address */ | ||
| 320 | discover_packet.hlen=ETHERNET_HARDWARE_ADDRESS_LENGTH; | ||
| 321 | |||
| 322 | discover_packet.hops=0; | ||
| 323 | |||
| 324 | /* transaction id is supposed to be random */ | ||
| 325 | srand(time(NULL)); | ||
| 326 | packet_xid=random(); | ||
| 327 | discover_packet.xid=htonl(packet_xid); | ||
| 328 | |||
| 329 | /**** WHAT THE HECK IS UP WITH THIS?!? IF I DON'T MAKE THIS CALL, ONLY ONE SERVER RESPONSE IS PROCESSED!!!! ****/ | ||
| 330 | /* downright bizzarre... */ | ||
| 331 | ntohl(discover_packet.xid); | ||
| 332 | |||
| 333 | /*discover_packet.secs=htons(65535);*/ | ||
| 334 | discover_packet.secs=0xFF; | ||
| 335 | |||
| 336 | /* tell server it should broadcast its response */ | ||
| 337 | discover_packet.flags=htons(DHCP_BROADCAST_FLAG); | ||
| 338 | |||
| 339 | /* our hardware address */ | ||
| 340 | memcpy(discover_packet.chaddr,client_hardware_address,ETHERNET_HARDWARE_ADDRESS_LENGTH); | ||
| 341 | |||
| 342 | /* first four bytes of options field is magic cookie (as per RFC 2132) */ | ||
| 343 | discover_packet.options[0]='\x63'; | ||
| 344 | discover_packet.options[1]='\x82'; | ||
| 345 | discover_packet.options[2]='\x53'; | ||
| 346 | discover_packet.options[3]='\x63'; | ||
| 347 | |||
| 348 | /* DHCP message type is embedded in options field */ | ||
| 349 | discover_packet.options[4]=DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ | ||
| 350 | discover_packet.options[5]='\x01'; /* DHCP message option length in bytes */ | ||
| 351 | discover_packet.options[6]=DHCPDISCOVER; | ||
| 352 | |||
| 353 | /* the IP address we're requesting */ | ||
| 354 | if(request_specific_address==TRUE){ | ||
| 355 | discover_packet.options[7]=DHCP_OPTION_REQUESTED_ADDRESS; | ||
| 356 | discover_packet.options[8]='\x04'; | ||
| 357 | memcpy(&discover_packet.options[9],&requested_address,sizeof(requested_address)); | ||
| 358 | } | ||
| 359 | |||
| 360 | /* send the DHCPDISCOVER packet to broadcast address */ | ||
| 361 | sockaddr_broadcast.sin_family=AF_INET; | ||
| 362 | sockaddr_broadcast.sin_port=htons(DHCP_SERVER_PORT); | ||
| 363 | sockaddr_broadcast.sin_addr.s_addr=INADDR_BROADCAST; | ||
| 364 | bzero(&sockaddr_broadcast.sin_zero,sizeof(sockaddr_broadcast.sin_zero)); | ||
| 365 | |||
| 366 | |||
| 367 | #ifdef DEBUG | ||
| 368 | printf("DHCPDISCOVER to %s port %d\n",inet_ntoa(sockaddr_broadcast.sin_addr),ntohs(sockaddr_broadcast.sin_port)); | ||
| 369 | printf("DHCPDISCOVER XID: %lu (0x%X)\n",ntohl(discover_packet.xid),ntohl(discover_packet.xid)); | ||
| 370 | printf("DHCDISCOVER ciaddr: %s\n",inet_ntoa(discover_packet.ciaddr)); | ||
| 371 | printf("DHCDISCOVER yiaddr: %s\n",inet_ntoa(discover_packet.yiaddr)); | ||
| 372 | printf("DHCDISCOVER siaddr: %s\n",inet_ntoa(discover_packet.siaddr)); | ||
| 373 | printf("DHCDISCOVER giaddr: %s\n",inet_ntoa(discover_packet.giaddr)); | ||
| 374 | #endif | ||
| 375 | |||
| 376 | /* send the DHCPDISCOVER packet out */ | ||
| 377 | send_dhcp_packet(&discover_packet,sizeof(discover_packet),sock,&sockaddr_broadcast); | ||
| 378 | |||
| 379 | #ifdef DEBUG | ||
| 380 | printf("\n\n"); | ||
| 381 | #endif | ||
| 382 | |||
| 383 | return OK; | ||
| 384 | } | ||
| 385 | |||
| 386 | |||
| 387 | |||
| 388 | |||
| 389 | /* waits for a DHCPOFFER message from one or more DHCP servers */ | ||
| 390 | int get_dhcp_offer(int sock){ | ||
| 391 | dhcp_packet offer_packet; | ||
| 392 | struct sockaddr_in source; | ||
| 393 | int result=OK; | ||
| 394 | int timeout=1; | ||
| 395 | int responses=0; | ||
| 396 | int x; | ||
| 397 | time_t start_time; | ||
| 398 | time_t current_time; | ||
| 399 | |||
| 400 | time(&start_time); | ||
| 401 | |||
| 402 | /* receive as many responses as we can */ | ||
| 403 | for(responses=0,valid_responses=0;;){ | ||
| 404 | |||
| 405 | time(¤t_time); | ||
| 406 | if((current_time-start_time)>=dhcpoffer_timeout) | ||
| 407 | break; | ||
| 408 | |||
| 409 | #ifdef DEBUG | ||
| 410 | printf("\n\n"); | ||
| 411 | #endif | ||
| 412 | |||
| 413 | bzero(&source,sizeof(source)); | ||
| 414 | bzero(&offer_packet,sizeof(offer_packet)); | ||
| 415 | |||
| 416 | result=OK; | ||
| 417 | result=receive_dhcp_packet(&offer_packet,sizeof(offer_packet),sock,dhcpoffer_timeout,&source); | ||
| 418 | |||
| 419 | if(result!=OK){ | ||
| 420 | #ifdef DEBUG | ||
| 421 | printf("Result=ERROR\n"); | ||
| 422 | #endif | ||
| 423 | continue; | ||
| 424 | } | ||
| 425 | else{ | ||
| 426 | #ifdef DEBUG | ||
| 427 | printf("Result=OK\n"); | ||
| 428 | #endif | ||
| 429 | responses++; | ||
| 430 | } | ||
| 431 | |||
| 432 | #ifdef DEBUG | ||
| 433 | printf("DHCPOFFER from IP address %s\n",inet_ntoa(source.sin_addr)); | ||
| 434 | printf("DHCPOFFER XID: %lu (0x%X)\n",ntohl(offer_packet.xid),ntohl(offer_packet.xid)); | ||
| 435 | #endif | ||
| 436 | |||
| 437 | /* check packet xid to see if its the same as the one we used in the discover packet */ | ||
| 438 | if(ntohl(offer_packet.xid)!=packet_xid){ | ||
| 439 | #ifdef DEBUG | ||
| 440 | printf("DHCPOFFER XID (%lu) did not match DHCPDISCOVER XID (%lu) - ignoring packet\n",ntohl(offer_packet.xid),packet_xid); | ||
| 441 | #endif | ||
| 442 | continue; | ||
| 443 | } | ||
| 444 | |||
| 445 | /* check hardware address */ | ||
| 446 | result=OK; | ||
| 447 | #ifdef DEBUG | ||
| 448 | printf("DHCPOFFER chaddr: "); | ||
| 449 | #endif | ||
| 450 | for(x=0;x<ETHERNET_HARDWARE_ADDRESS_LENGTH;x++){ | ||
| 451 | #ifdef DEBUG | ||
| 452 | printf("%02X",(unsigned char)offer_packet.chaddr[x]); | ||
| 453 | #endif | ||
| 454 | if(offer_packet.chaddr[x]!=client_hardware_address[x]){ | ||
| 455 | result=ERROR; | ||
| 456 | } | ||
| 457 | } | ||
| 458 | #ifdef DEBUG | ||
| 459 | printf("\n"); | ||
| 460 | #endif | ||
| 461 | if(result==ERROR){ | ||
| 462 | #ifdef DEBUG | ||
| 463 | printf("DHCPOFFER hardware address did not match our own - ignoring packet\n"); | ||
| 464 | #endif | ||
| 465 | continue; | ||
| 466 | } | ||
| 467 | |||
| 468 | #ifdef DEBUG | ||
| 469 | printf("DHCPOFFER ciaddr: %s\n",inet_ntoa(offer_packet.ciaddr)); | ||
| 470 | printf("DHCPOFFER yiaddr: %s\n",inet_ntoa(offer_packet.yiaddr)); | ||
| 471 | printf("DHCPOFFER siaddr: %s\n",inet_ntoa(offer_packet.siaddr)); | ||
| 472 | printf("DHCPOFFER giaddr: %s\n",inet_ntoa(offer_packet.giaddr)); | ||
| 473 | #endif | ||
| 474 | |||
| 475 | add_dhcp_offer(source.sin_addr,&offer_packet); | ||
| 476 | |||
| 477 | valid_responses++; | ||
| 478 | } | ||
| 479 | |||
| 480 | #ifdef DEBUG | ||
| 481 | printf("Total responses seen on the wire: %d\n",responses); | ||
| 482 | printf("Valid responses for this machine: %d\n",valid_responses); | ||
| 483 | #endif | ||
| 484 | |||
| 485 | return OK; | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | |||
| 490 | /* sends a DHCP packet */ | ||
| 491 | int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest){ | ||
| 492 | struct sockaddr_in myname; | ||
| 493 | int result; | ||
| 494 | |||
| 495 | result=sendto(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)dest,sizeof(*dest)); | ||
| 496 | |||
| 497 | #ifdef DEBUG | ||
| 498 | printf("send_dhcp_packet result: %d\n",result); | ||
| 499 | #endif | ||
| 500 | |||
| 501 | if(result<0) | ||
| 502 | return ERROR; | ||
| 503 | |||
| 504 | return OK; | ||
| 505 | } | ||
| 506 | |||
| 507 | |||
| 508 | |||
| 509 | /* receives a DHCP packet */ | ||
| 510 | int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address){ | ||
| 511 | struct timeval tv; | ||
| 512 | fd_set readfds; | ||
| 513 | int recv_result; | ||
| 514 | socklen_t address_size; | ||
| 515 | struct sockaddr_in source_address; | ||
| 516 | |||
| 517 | |||
| 518 | /* wait for data to arrive (up time timeout) */ | ||
| 519 | tv.tv_sec=timeout; | ||
| 520 | tv.tv_usec=0; | ||
| 521 | FD_ZERO(&readfds); | ||
| 522 | FD_SET(sock,&readfds); | ||
| 523 | select(sock+1,&readfds,NULL,NULL,&tv); | ||
| 524 | |||
| 525 | /* make sure some data has arrived */ | ||
| 526 | if(!FD_ISSET(sock,&readfds)){ | ||
| 527 | #ifdef DEBUG | ||
| 528 | printf("No (more) data received\n"); | ||
| 529 | #endif | ||
| 530 | return ERROR; | ||
| 531 | } | ||
| 532 | |||
| 533 | else{ | ||
| 534 | |||
| 535 | /* why do we need to peek first? i don't know, its a hack. without it, the source address of the first packet received was | ||
| 536 | not being interpreted correctly. sigh... */ | ||
| 537 | bzero(&source_address,sizeof(source_address)); | ||
| 538 | address_size=sizeof(source_address); | ||
| 539 | recv_result=recvfrom(sock,(char *)buffer,buffer_size,MSG_PEEK,(struct sockaddr *)&source_address,&address_size); | ||
| 540 | #ifdef DEBUG | ||
| 541 | printf("recv_result_1: %d\n",recv_result); | ||
| 542 | #endif | ||
| 543 | recv_result=recvfrom(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)&source_address,&address_size); | ||
| 544 | #ifdef DEBUG | ||
| 545 | printf("recv_result_2: %d\n",recv_result); | ||
| 546 | #endif | ||
| 547 | |||
| 548 | if(recv_result==-1){ | ||
| 549 | #ifdef DEBUG | ||
| 550 | printf("recvfrom() failed, "); | ||
| 551 | printf("errno: (%d) -> %s\n",errno,strerror(errno)); | ||
| 552 | #endif | ||
| 553 | return ERROR; | ||
| 554 | } | ||
| 555 | else{ | ||
| 556 | #ifdef DEBUG | ||
| 557 | printf("receive_dhcp_packet() result: %d\n",recv_result); | ||
| 558 | printf("receive_dhcp_packet() source: %s\n",inet_ntoa(source_address.sin_addr)); | ||
| 559 | #endif | ||
| 560 | |||
| 561 | memcpy(address,&source_address,sizeof(source_address)); | ||
| 562 | return OK; | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 566 | return OK; | ||
| 567 | } | ||
| 568 | |||
| 569 | |||
| 570 | |||
| 571 | /* creates a socket for DHCP communication */ | ||
| 572 | int create_dhcp_socket(void){ | ||
| 573 | struct sockaddr_in myname; | ||
| 574 | struct ifreq interface; | ||
| 575 | int sock; | ||
| 576 | int flag=1; | ||
| 577 | |||
| 578 | /* Set up the address we're going to bind to. */ | ||
| 579 | bzero(&myname,sizeof(myname)); | ||
| 580 | myname.sin_family=AF_INET; | ||
| 581 | myname.sin_port=htons(DHCP_CLIENT_PORT); | ||
| 582 | myname.sin_addr.s_addr=INADDR_ANY; /* listen on any address */ | ||
| 583 | bzero(&myname.sin_zero,sizeof(myname.sin_zero)); | ||
| 584 | |||
| 585 | /* create a socket for DHCP communications */ | ||
| 586 | sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); | ||
| 587 | if(sock<0){ | ||
| 588 | printf("Error: Could not create socket!\n"); | ||
| 589 | exit(STATE_UNKNOWN); | ||
| 590 | } | ||
| 591 | |||
| 592 | #ifdef DEBUG | ||
| 593 | printf("DHCP socket: %d\n",sock); | ||
| 594 | #endif | ||
| 595 | |||
| 596 | /* set the reuse address flag so we don't get errors when restarting */ | ||
| 597 | flag=1; | ||
| 598 | if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag))<0){ | ||
| 599 | printf("Error: Could not set reuse address option on DHCP socket!\n"); | ||
| 600 | exit(STATE_UNKNOWN); | ||
| 601 | } | ||
| 602 | |||
| 603 | /* set the broadcast option - we need this to listen to DHCP broadcast messages */ | ||
| 604 | if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&flag,sizeof flag)<0){ | ||
| 605 | printf("Error: Could not set broadcast option on DHCP socket!\n"); | ||
| 606 | exit(STATE_UNKNOWN); | ||
| 607 | } | ||
| 608 | |||
| 609 | /* bind socket to interface */ | ||
| 610 | #if defined(__linux__) | ||
| 611 | strncpy(interface.ifr_ifrn.ifrn_name,network_interface_name,IFNAMSIZ); | ||
| 612 | if(setsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,(char *)&interface,sizeof(interface))<0){ | ||
| 613 | printf("Error: Could not bind socket to interface %s. Check your privileges...\n",network_interface_name); | ||
| 614 | exit(STATE_UNKNOWN); | ||
| 615 | } | ||
| 616 | |||
| 617 | #else | ||
| 618 | strncpy(interface.ifr_name,network_interface_name,IFNAMSIZ); | ||
| 619 | #endif | ||
| 620 | |||
| 621 | /* bind the socket */ | ||
| 622 | if(bind(sock,(struct sockaddr *)&myname,sizeof(myname))<0){ | ||
| 623 | printf("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n",DHCP_CLIENT_PORT); | ||
| 624 | exit(STATE_UNKNOWN); | ||
| 625 | } | ||
| 626 | |||
| 627 | return sock; | ||
| 628 | } | ||
| 629 | |||
| 630 | |||
| 631 | |||
| 632 | |||
| 633 | |||
| 634 | /* closes DHCP socket */ | ||
| 635 | int close_dhcp_socket(int sock){ | ||
| 636 | |||
| 637 | close(sock); | ||
| 638 | |||
| 639 | return OK; | ||
| 640 | } | ||
| 641 | |||
| 642 | |||
| 643 | |||
| 644 | |||
| 645 | /* adds a requested server address to list in memory */ | ||
| 646 | int add_requested_server(struct in_addr server_address){ | ||
| 647 | requested_server *new_server; | ||
| 648 | |||
| 649 | new_server=(requested_server *)malloc(sizeof(requested_server)); | ||
| 650 | if(new_server==NULL) | ||
| 651 | return ERROR; | ||
| 652 | |||
| 653 | new_server->server_address=server_address; | ||
| 654 | |||
| 655 | new_server->next=requested_server_list; | ||
| 656 | requested_server_list=new_server; | ||
| 657 | |||
| 658 | requested_servers++; | ||
| 659 | |||
| 660 | #ifdef DEBUG | ||
| 661 | printf("Requested server address: %s\n",inet_ntoa(new_server->server_address)); | ||
| 662 | #endif | ||
| 663 | |||
| 664 | return OK; | ||
| 665 | } | ||
| 666 | |||
| 667 | |||
| 668 | |||
| 669 | |||
| 670 | /* adds a DHCP OFFER to list in memory */ | ||
| 671 | int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){ | ||
| 672 | dhcp_offer *new_offer; | ||
| 673 | int x; | ||
| 674 | int y; | ||
| 675 | unsigned option_type; | ||
| 676 | unsigned option_length; | ||
| 677 | |||
| 678 | if(offer_packet==NULL) | ||
| 679 | return ERROR; | ||
| 680 | |||
| 681 | /* process all DHCP options present in the packet */ | ||
| 682 | for(x=4;x<MAX_DHCP_OPTIONS_LENGTH;){ | ||
| 683 | |||
| 684 | /* end of options (0 is really just a pad, but bail out anyway) */ | ||
| 685 | if((int)offer_packet->options[x]==-1 || (int)offer_packet->options[x]==0) | ||
| 686 | break; | ||
| 687 | |||
| 688 | /* get option type */ | ||
| 689 | option_type=offer_packet->options[x++]; | ||
| 690 | |||
| 691 | /* get option length */ | ||
| 692 | option_length=offer_packet->options[x++]; | ||
| 693 | |||
| 694 | #ifdef DEBUG | ||
| 695 | printf("Option: %d (0x%02X)\n",option_type,option_length); | ||
| 696 | #endif | ||
| 697 | |||
| 698 | /* get option data */ | ||
| 699 | if(option_type==DHCP_OPTION_LEASE_TIME) | ||
| 700 | dhcp_lease_time=ntohl(*((u_int32_t *)&offer_packet->options[x])); | ||
| 701 | if(option_type==DHCP_OPTION_RENEWAL_TIME) | ||
| 702 | dhcp_renewal_time=ntohl(*((u_int32_t *)&offer_packet->options[x])); | ||
| 703 | if(option_type==DHCP_OPTION_REBINDING_TIME) | ||
| 704 | dhcp_rebinding_time=ntohl(*((u_int32_t *)&offer_packet->options[x])); | ||
| 705 | |||
| 706 | /* skip option data we're ignoring */ | ||
| 707 | else | ||
| 708 | for(y=0;y<option_length;y++,x++); | ||
| 709 | } | ||
| 710 | |||
| 711 | #ifdef DEBUG | ||
| 712 | if(dhcp_lease_time==DHCP_INFINITE_TIME) | ||
| 713 | printf("Lease Time: Infinite\n"); | ||
| 714 | else | ||
| 715 | printf("Lease Time: %lu seconds\n",(unsigned long)dhcp_lease_time); | ||
| 716 | if(dhcp_renewal_time==DHCP_INFINITE_TIME) | ||
| 717 | printf("Renewal Time: Infinite\n"); | ||
| 718 | else | ||
| 719 | printf("Renewal Time: %lu seconds\n",(unsigned long)dhcp_renewal_time); | ||
| 720 | if(dhcp_rebinding_time==DHCP_INFINITE_TIME) | ||
| 721 | printf("Rebinding Time: Infinite\n"); | ||
| 722 | printf("Rebinding Time: %lu seconds\n",(unsigned long)dhcp_rebinding_time); | ||
| 723 | #endif | ||
| 724 | |||
| 725 | new_offer=(dhcp_offer *)malloc(sizeof(dhcp_offer)); | ||
| 726 | |||
| 727 | if(new_offer==NULL) | ||
| 728 | return ERROR; | ||
| 729 | |||
| 730 | |||
| 731 | new_offer->server_address=source; | ||
| 732 | new_offer->offered_address=offer_packet->yiaddr; | ||
| 733 | new_offer->lease_time=dhcp_lease_time; | ||
| 734 | new_offer->renewal_time=dhcp_renewal_time; | ||
| 735 | new_offer->rebinding_time=dhcp_rebinding_time; | ||
| 736 | |||
| 737 | |||
| 738 | #ifdef DEBUG | ||
| 739 | printf("Added offer from server @ %s",inet_ntoa(new_offer->server_address)); | ||
| 740 | printf(" of IP address %s\n",inet_ntoa(new_offer->offered_address)); | ||
| 741 | #endif | ||
| 742 | |||
| 743 | /* add new offer to head of list */ | ||
| 744 | new_offer->next=dhcp_offer_list; | ||
| 745 | dhcp_offer_list=new_offer; | ||
| 746 | |||
| 747 | return OK; | ||
| 748 | } | ||
| 749 | |||
| 750 | |||
| 751 | |||
| 752 | |||
| 753 | /* frees memory allocated to DHCP OFFER list */ | ||
| 754 | int free_dhcp_offer_list(void){ | ||
| 755 | dhcp_offer *this_offer; | ||
| 756 | dhcp_offer *next_offer; | ||
| 757 | |||
| 758 | for(this_offer=dhcp_offer_list;this_offer!=NULL;this_offer=next_offer){ | ||
| 759 | next_offer=this_offer->next; | ||
| 760 | free(this_offer); | ||
| 761 | } | ||
| 762 | |||
| 763 | return OK; | ||
| 764 | } | ||
| 765 | |||
| 766 | |||
| 767 | |||
| 768 | |||
| 769 | /* frees memory allocated to requested server list */ | ||
| 770 | int free_requested_server_list(void){ | ||
| 771 | requested_server *this_server; | ||
| 772 | requested_server *next_server; | ||
| 773 | |||
| 774 | for(this_server=requested_server_list;this_server!=NULL;this_server=next_server){ | ||
| 775 | next_server=this_server->next; | ||
| 776 | free(this_server); | ||
| 777 | } | ||
| 778 | |||
| 779 | return OK; | ||
| 780 | } | ||
| 781 | |||
| 782 | |||
| 783 | /* gets state and plugin output to return */ | ||
| 784 | int get_results(void){ | ||
| 785 | dhcp_offer *temp_offer; | ||
| 786 | requested_server *temp_server; | ||
| 787 | int result; | ||
| 788 | u_int32_t max_lease_time=0; | ||
| 789 | |||
| 790 | received_requested_address=FALSE; | ||
| 791 | |||
| 792 | /* checks responses from requested servers */ | ||
| 793 | requested_responses=0; | ||
| 794 | if(requested_servers>0){ | ||
| 795 | |||
| 796 | for(temp_server=requested_server_list;temp_server!=NULL;temp_server=temp_server->next){ | ||
| 797 | |||
| 798 | for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next){ | ||
| 799 | |||
| 800 | /* get max lease time we were offered */ | ||
| 801 | if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) | ||
| 802 | max_lease_time=temp_offer->lease_time; | ||
| 803 | |||
| 804 | /* see if we got the address we requested */ | ||
| 805 | if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) | ||
| 806 | received_requested_address=TRUE; | ||
| 807 | |||
| 808 | /* see if the servers we wanted a response from talked to us or not */ | ||
| 809 | if(!memcmp(&temp_offer->server_address,&temp_server->server_address,sizeof(temp_server->server_address))){ | ||
| 810 | #ifdef DEBUG | ||
| 811 | printf("DHCP Server Match: Offerer=%s",inet_ntoa(temp_offer->server_address)); | ||
| 812 | printf(" Requested=%s\n",inet_ntoa(temp_server->server_address)); | ||
| 813 | #endif | ||
| 814 | requested_responses++; | ||
| 815 | } | ||
| 816 | } | ||
| 817 | } | ||
| 818 | |||
| 819 | } | ||
| 820 | |||
| 821 | /* else check and see if we got our requested address from any server */ | ||
| 822 | else{ | ||
| 823 | |||
| 824 | for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next){ | ||
| 825 | |||
| 826 | /* get max lease time we were offered */ | ||
| 827 | if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) | ||
| 828 | max_lease_time=temp_offer->lease_time; | ||
| 829 | |||
| 830 | /* see if we got the address we requested */ | ||
| 831 | if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) | ||
| 832 | received_requested_address=TRUE; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | result=STATE_OK; | ||
| 837 | if(valid_responses==0) | ||
| 838 | result=STATE_CRITICAL; | ||
| 839 | else if(requested_servers>0 && requested_responses==0) | ||
| 840 | result=STATE_CRITICAL; | ||
| 841 | else if(requested_responses<requested_servers) | ||
| 842 | result=STATE_WARNING; | ||
| 843 | else if(request_specific_address==TRUE && received_requested_address==FALSE) | ||
| 844 | result=STATE_WARNING; | ||
| 845 | |||
| 846 | |||
| 847 | printf("DHCP %s: ",(result==STATE_OK)?"ok":"problem"); | ||
| 848 | |||
| 849 | /* we didn't receive any DHCPOFFERs */ | ||
| 850 | if(dhcp_offer_list==NULL){ | ||
| 851 | printf("No DHCPOFFERs were received.\n"); | ||
| 852 | return result; | ||
| 853 | } | ||
| 854 | |||
| 855 | printf("Received %d DHCPOFFER(s)",valid_responses); | ||
| 856 | |||
| 857 | if(requested_servers>0) | ||
| 858 | printf(", %s%d of %d requested servers responded",((requested_responses<requested_servers) && requested_responses>0)?"only ":"",requested_responses,requested_servers); | ||
| 859 | |||
| 860 | if(request_specific_address==TRUE) | ||
| 861 | printf(", requested address (%s) was %soffered",inet_ntoa(requested_address),(received_requested_address==TRUE)?"":"not "); | ||
| 862 | |||
| 863 | printf(", max lease time = "); | ||
| 864 | if(max_lease_time==DHCP_INFINITE_TIME) | ||
| 865 | printf("Infinity"); | ||
| 866 | else | ||
| 867 | printf("%lu sec",(unsigned long)max_lease_time); | ||
| 868 | |||
| 869 | printf(".\n"); | ||
| 870 | |||
| 871 | return result; | ||
| 872 | } | ||
| 873 | |||
| 874 | |||
| 875 | |||
| 876 | |||
| 877 | |||
| 878 | |||
| 879 | /* print usage help */ | ||
| 880 | void print_help(void){ | ||
| 881 | |||
| 882 | /*print_revision(progname,"$Revision$");*/ | ||
| 883 | |||
| 884 | printf("Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n\n"); | ||
| 885 | printf("This plugin tests the availability of DHCP servers on a network.\n\n"); | ||
| 886 | |||
| 887 | print_usage(); | ||
| 888 | |||
| 889 | printf | ||
| 890 | ("\nOptions:\n" | ||
| 891 | " -s, --serverip=IPADDRESS\n" | ||
| 892 | " IP address of DHCP server that we must hear from\n" | ||
| 893 | " -r, --requestedip=IPADDRESS\n" | ||
| 894 | " IP address that should be offered by at least one DHCP server\n" | ||
| 895 | " -t, --timeout=INTEGER\n" | ||
| 896 | " Seconds to wait for DHCPOFFER before timeout occurs\n" | ||
| 897 | " -i, --interface=STRING\n" | ||
| 898 | " Interface to to use for listening (i.e. eth0)\n" | ||
| 899 | " -v, --verbose\n" | ||
| 900 | " Print extra information (command-line use only)\n" | ||
| 901 | " -h, --help\n" | ||
| 902 | " Print detailed help screen\n" | ||
| 903 | " -V, --version\n" | ||
| 904 | " Print version information\n\n" | ||
| 905 | ); | ||
| 906 | |||
| 907 | /*support();*/ | ||
| 908 | |||
| 909 | return; | ||
| 910 | } | ||
| 911 | |||
| 912 | |||
| 913 | /* prints usage information */ | ||
| 914 | void print_usage(void){ | ||
| 915 | |||
| 916 | printf("Usage: %s [-s serverip] [-r requestedip] [-t timeout] [-i interface]\n",progname); | ||
| 917 | printf(" %s --help\n",progname); | ||
| 918 | printf(" %s --version\n",progname); | ||
| 919 | |||
| 920 | return; | ||
| 921 | } | ||
| 922 | |||
| 923 | |||
| 924 | |||
| 925 | |||
| 926 | /* process command-line arguments */ | ||
| 927 | int process_arguments(int argc, char **argv){ | ||
| 928 | int c; | ||
| 929 | |||
| 930 | if(argc<1) | ||
| 931 | return ERROR; | ||
| 932 | |||
| 933 | c=0; | ||
| 934 | while((c+=(call_getopt(argc-c,&argv[c])))<argc){ | ||
| 935 | |||
| 936 | /* | ||
| 937 | if(is_option(argv[c])) | ||
| 938 | continue; | ||
| 939 | */ | ||
| 940 | } | ||
| 941 | |||
| 942 | return validate_arguments(); | ||
| 943 | } | ||
| 944 | |||
| 945 | |||
| 946 | |||
| 947 | int call_getopt(int argc, char **argv){ | ||
| 948 | int c=0; | ||
| 949 | int i=0; | ||
| 950 | struct in_addr ipaddress; | ||
| 951 | |||
| 952 | #ifdef HAVE_GETOPT_H | ||
| 953 | int option_index = 0; | ||
| 954 | static struct option long_options[] = | ||
| 955 | { | ||
| 956 | {"serverip", required_argument,0,'s'}, | ||
| 957 | {"requestedip", required_argument,0,'r'}, | ||
| 958 | {"timeout", required_argument,0,'t'}, | ||
| 959 | {"interface", required_argument,0,'i'}, | ||
| 960 | {"verbose", no_argument, 0,'v'}, | ||
| 961 | {"version", no_argument, 0,'V'}, | ||
| 962 | {"help", no_argument, 0,'h'}, | ||
| 963 | {0,0,0,0} | ||
| 964 | }; | ||
| 965 | #endif | ||
| 966 | |||
| 967 | while(1){ | ||
| 968 | #ifdef HAVE_GETOPT_H | ||
| 969 | c=getopt_long(argc,argv,"+hVvt:s:r:t:i:",long_options,&option_index); | ||
| 970 | #else | ||
| 971 | c=getopt(argc,argv,"+?hVvt:s:r:t:i:"); | ||
| 972 | #endif | ||
| 973 | |||
| 974 | i++; | ||
| 975 | |||
| 976 | if(c==-1||c==EOF||c==1) | ||
| 977 | break; | ||
| 978 | |||
| 979 | switch(c){ | ||
| 980 | case 'w': | ||
| 981 | case 'r': | ||
| 982 | case 't': | ||
| 983 | case 'i': | ||
| 984 | i++; | ||
| 985 | break; | ||
| 986 | default: | ||
| 987 | break; | ||
| 988 | } | ||
| 989 | |||
| 990 | switch(c){ | ||
| 991 | |||
| 992 | case 's': /* DHCP server address */ | ||
| 993 | if(inet_aton(optarg,&ipaddress)) | ||
| 994 | add_requested_server(ipaddress); | ||
| 995 | /* | ||
| 996 | else | ||
| 997 | usage("Invalid server IP address\n"); | ||
| 998 | */ | ||
| 999 | break; | ||
| 1000 | |||
| 1001 | case 'r': /* address we are requested from DHCP servers */ | ||
| 1002 | if(inet_aton(optarg,&ipaddress)){ | ||
| 1003 | requested_address=ipaddress; | ||
| 1004 | request_specific_address=TRUE; | ||
| 1005 | } | ||
| 1006 | /* | ||
| 1007 | else | ||
| 1008 | usage("Invalid requested IP address\n"); | ||
| 1009 | */ | ||
| 1010 | break; | ||
| 1011 | |||
| 1012 | case 't': /* timeout */ | ||
| 1013 | |||
| 1014 | /* | ||
| 1015 | if(is_intnonneg(optarg)) | ||
| 1016 | */ | ||
| 1017 | if(atoi(optarg)>0) | ||
| 1018 | dhcpoffer_timeout=atoi(optarg); | ||
| 1019 | /* | ||
| 1020 | else | ||
| 1021 | usage("Time interval must be a nonnegative integer\n"); | ||
| 1022 | */ | ||
| 1023 | break; | ||
| 1024 | |||
| 1025 | case 'i': /* interface name */ | ||
| 1026 | |||
| 1027 | strncpy(network_interface_name,optarg,sizeof(network_interface_name)-1); | ||
| 1028 | network_interface_name[sizeof(network_interface_name)-1]='\x0'; | ||
| 1029 | |||
| 1030 | break; | ||
| 1031 | |||
| 1032 | case 'V': /* version */ | ||
| 1033 | |||
| 1034 | /*print_revision(progname,"$Revision$");*/ | ||
| 1035 | exit(STATE_OK); | ||
| 1036 | |||
| 1037 | case 'h': /* help */ | ||
| 1038 | |||
| 1039 | print_help(); | ||
| 1040 | exit(STATE_OK); | ||
| 1041 | |||
| 1042 | case '?': /* help */ | ||
| 1043 | |||
| 1044 | /*usage("Invalid argument\n");*/ | ||
| 1045 | break; | ||
| 1046 | |||
| 1047 | default: | ||
| 1048 | break; | ||
| 1049 | } | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | return i; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | |||
| 1056 | |||
| 1057 | int validate_arguments(void){ | ||
| 1058 | |||
| 1059 | return OK; | ||
| 1060 | } | ||
| 1061 | |||
