~ubuntu-branches/ubuntu/precise/nagios-plugins/precise-proposed

« back to all changes in this revision

Viewing changes to contrib/check_dhcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Trotter
  • Date: 2004-06-15 15:37:48 UTC
  • Revision ID: james.westby@ubuntu.com-20040615153748-pq7702qdzghqfcns
Tags: upstream-1.3.1.0
ImportĀ upstreamĀ versionĀ 1.3.1.0

Show diffs side-by-side

added added

removed removed

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