summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/Makefile.am8
-rw-r--r--plugins/check_dhcp.c1061
2 files changed, 1066 insertions, 3 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index b87154d..33f7686 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -10,7 +10,7 @@ localedir = $(datadir)/locale
10DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ 10DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
11LIBS = @LIBINTL@ @LIBS@ 11LIBS = @LIBINTL@ @LIBS@
12 12
13libexec_PROGRAMS = check_disk check_dummy check_http check_load \ 13libexec_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
47check_dhcp_LDADD = $(BASEOBJS)
47check_dig_LDADD = $(NETLIBS) popen.o 48check_dig_LDADD = $(NETLIBS) popen.o
48check_disk_LDADD = $(BASEOBJS) popen.o 49check_disk_LDADD = $(BASEOBJS) popen.o
49check_dns_LDADD = $(NETLIBS) popen.o 50check_dns_LDADD = $(NETLIBS) popen.o
@@ -80,6 +81,7 @@ check_ide_smart_LDADD = $(BASEOBJS)
80negate_LDADD = $(BASEOBJS) popen.o 81negate_LDADD = $(BASEOBJS) popen.o
81urlize_LDADD = $(BASEOBJS) popen.o 82urlize_LDADD = $(BASEOBJS) popen.o
82 83
84check_dhcp_DEPENDENCIES = check_dhcp.c $(DEPLIBS)
83check_dig_DEPENDENCIES = check_dig.c $(NETOBJS) popen.o $(DEPLIBS) 85check_dig_DEPENDENCIES = check_dig.c $(NETOBJS) popen.o $(DEPLIBS)
84check_disk_DEPENDENCIES = check_disk.c $(BASEOBJS) popen.o $(DEPLIBS) 86check_disk_DEPENDENCIES = check_disk.c $(BASEOBJS) popen.o $(DEPLIBS)
85check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) popen.o $(DEPLIBS) 87check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) popen.o $(DEPLIBS)
@@ -88,6 +90,8 @@ check_fping_DEPENDENCIES = check_fping.c $(NETOBJS) popen.o $(DEPLIBS)
88check_game_DEPENDENCIES = check_game.c $(DEPLIBS) 90check_game_DEPENDENCIES = check_game.c $(DEPLIBS)
89check_http_DEPENDENCIES = check_http.c $(NETOBJS) $(DEPLIBS) 91check_http_DEPENDENCIES = check_http.c $(NETOBJS) $(DEPLIBS)
90check_hpjd_DEPENDENCIES = check_hpjd.c $(NETOBJS) popen.o $(DEPLIBS) 92check_hpjd_DEPENDENCIES = check_hpjd.c $(NETOBJS) popen.o $(DEPLIBS)
93check_icmp_DEPENDENCIES = check_icmp.c $(DEPLIBS)
94check_ide_smart_DEPENDENCIES = check_ide_smart.c $(BASEOBJS) $(DEPLIBS)
91check_ldap_DEPENDENCIES = check_ldap.c $(NETOBJS) $(DEPLIBS) 95check_ldap_DEPENDENCIES = check_ldap.c $(NETOBJS) $(DEPLIBS)
92check_load_DEPENDENCIES = check_load.c $(BASEOBJS) popen.o $(DEPLIBS) 96check_load_DEPENDENCIES = check_load.c $(BASEOBJS) popen.o $(DEPLIBS)
93check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS) 97check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS)
@@ -112,10 +116,8 @@ check_udp_DEPENDENCIES = check_udp.c $(NETOBJS) $(DEPLIBS)
112check_ups_DEPENDENCIES = check_ups.c $(NETOBJS) $(DEPLIBS) 116check_ups_DEPENDENCIES = check_ups.c $(NETOBJS) $(DEPLIBS)
113check_users_DEPENDENCIES = check_users.c $(BASEOBJS) popen.o $(DEPLIBS) 117check_users_DEPENDENCIES = check_users.c $(BASEOBJS) popen.o $(DEPLIBS)
114check_by_ssh_DEPENDENCIES = check_by_ssh.c $(NETOBJS) popen.o $(DEPLIBS) 118check_by_ssh_DEPENDENCIES = check_by_ssh.c $(NETOBJS) popen.o $(DEPLIBS)
115check_ide_smart_DEPENDENCIES = check_ide_smart.c $(BASEOBJS) $(DEPLIBS)
116negate_DEPENDENCIES = negate.c $(BASEOBJS) popen.o $(DEPLIBS) 119negate_DEPENDENCIES = negate.c $(BASEOBJS) popen.o $(DEPLIBS)
117urlize_DEPENDENCIES = urlize.c $(BASEOBJS) popen.o $(DEPLIBS) 120urlize_DEPENDENCIES = urlize.c $(BASEOBJS) popen.o $(DEPLIBS)
118check_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 0000000..ee893cd
--- /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
56const 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
84typedef 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
103typedef 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
113typedef 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
148unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]="";
149
150char network_interface_name[8]="eth0";
151
152u_int32_t packet_xid=0;
153
154u_int32_t dhcp_lease_time=0;
155u_int32_t dhcp_renewal_time=0;
156u_int32_t dhcp_rebinding_time=0;
157
158int dhcpoffer_timeout=2;
159
160dhcp_offer *dhcp_offer_list=NULL;
161requested_server *requested_server_list=NULL;
162
163int valid_responses=0; /* number of valid DHCPOFFERs we received */
164int requested_servers=0;
165int requested_responses=0;
166
167int request_specific_address=FALSE;
168int received_requested_address=FALSE;
169struct in_addr requested_address;
170
171
172int process_arguments(int, char **);
173int call_getopt(int, char **);
174int validate_arguments(void);
175void print_usage(void);
176void print_help(void);
177
178int get_hardware_address(int,char *);
179
180int send_dhcp_discover(int);
181int get_dhcp_offer(int);
182
183int get_results(void);
184
185int add_dhcp_offer(struct in_addr,dhcp_packet *);
186int free_dhcp_offer_list(void);
187int free_requested_server_list(void);
188
189int create_dhcp_socket(void);
190int close_dhcp_socket(int);
191int send_dhcp_packet(void *,int,int,struct sockaddr_in *);
192int receive_dhcp_packet(void *,int,int,int,struct sockaddr_in *);
193
194
195
196int 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 */
235int 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 */
304int 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 */
390int 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(&current_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 */
491int 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 */
510int 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 */
572int 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 */
635int 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 */
646int 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 */
671int 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 */
754int 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 */
770int 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 */
784int 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 */
880void 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 */
914void 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 */
927int 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
947int 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
1057int validate_arguments(void){
1058
1059 return OK;
1060 }
1061