X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=plugins-root%2Fcheck_dhcp.c;h=2a1875c405431048c3099a5ec8834ffd72599dcd;hb=b48c2bdd59783197c93cde531e6e8b9747c0a88f;hp=db673893ffb1d50a018e76740ee717bdfa89a1a8;hpb=6f60c0ac81933976fdc2e7e763fc1d03312e3b3f;p=nagiosplug.git diff --git a/plugins-root/check_dhcp.c b/plugins-root/check_dhcp.c index db67389..2a1875c 100644 --- a/plugins-root/check_dhcp.c +++ b/plugins-root/check_dhcp.c @@ -1,55 +1,47 @@ -/****************************************************************************** -* +/***************************************************************************** +* * Nagios check_dhcp plugin -* +* * License: GPL * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org) -* Copyright (c) 2001-2006 Nagios Plugin Development Team -* -* Last Modified: $Date$ -* +* Copyright (c) 2001-2007 Nagios Plugin Development Team +* * Description: -* +* * This file contains the check_dhcp plugin -* -* This plugin tests the availability of DHCP servers on a network. -* -* -* License Information: -* -* This program is free software; you can redistribute it and/or modify +* +* This plugin tests the availability of DHCP servers on a network. +* +* Unicast mode was originally implemented by Heiti of Boras Kommun with +* general improvements as well as usability fixes and "forward"-porting by +* Andreas Ericsson of OP5 AB. +* +* +* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or +* the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. -* +* * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* +* * You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* $Id$ -* -* ------------------------------------------------------------------------ -* Unicast mode was originally implemented by Heiti of Boras Kommun with -* general improvements as well as usability fixes and "forward"-porting by -* Andreas Ericsson of OP5 AB. -* ------------------------------------------------------------------------ -* +* along with this program. If not, see . +* +* *****************************************************************************/ const char *progname = "check_dhcp"; -const char *revision = "$Revision$"; -const char *copyright = "2001-2006"; +const char *copyright = "2001-2007"; const char *email = "nagiosplug-devel@lists.sourceforge.net"; #include "common.h" #include "netutils.h" #include "utils.h" +#include #include #include #include @@ -83,8 +75,8 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; #elif defined(__sun__) || defined(__solaris__) || defined(__hpux__) -#define INSAP 22 -#define OUTSAP 24 +#define INSAP 22 +#define OUTSAP 24 #include #include @@ -94,17 +86,17 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; #define bcopy(source, destination, length) memcpy(destination, source, length) -#define AREA_SZ 5000 /* buffer length in bytes */ +#define AREA_SZ 5000 /* buffer length in bytes */ static u_long ctl_area[AREA_SZ]; static u_long dat_area[AREA_SZ]; static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area}; static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area}; -#define GOT_CTRL 1 -#define GOT_DATA 2 -#define GOT_BOTH 3 -#define GOT_INTR 4 -#define GOT_ERR 128 +#define GOT_CTRL 1 +#define GOT_DATA 2 +#define GOT_BOTH 3 +#define GOT_INTR 4 +#define GOT_ERR 128 #define u_int8_t uint8_t #define u_int16_t uint16_t @@ -199,7 +191,6 @@ typedef struct requested_server_struct{ #define DHCP_INFINITE_TIME 0xFFFFFFFF #define DHCP_BROADCAST_FLAG 32768 -#define DHCP_UNICAST_FLAG 0 #define DHCP_SERVER_PORT 67 #define DHCP_CLIENT_PORT 68 @@ -211,6 +202,7 @@ u_int8_t unicast = 0; /* unicast mode: mimic a DHCP relay */ struct in_addr my_ip; /* our address (required for relay) */ struct in_addr dhcp_ip; /* server to query (if in unicast mode) */ unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]=""; +unsigned char *user_specified_mac=NULL; char network_interface_name[IFNAMSIZ]="eth0"; @@ -226,7 +218,7 @@ dhcp_offer *dhcp_offer_list=NULL; requested_server *requested_server_list=NULL; int valid_responses=0; /* number of valid DHCPOFFERs we received */ -int requested_servers=0; +int requested_servers=0; int requested_responses=0; int request_specific_address=FALSE; @@ -241,6 +233,9 @@ int validate_arguments(void); void print_usage(void); void print_help(void); +void resolve_host(const char *in,struct in_addr *out); +unsigned char *mac_aton(const char *); +void print_hardware_address(const unsigned char *); int get_hardware_address(int,char *); int get_ip_address(int,char *); @@ -264,22 +259,28 @@ int main(int argc, char **argv){ int dhcp_socket; int result = STATE_UNKNOWN; - /* this plugin almost certainly needs root permissions. */ - np_warn_if_not_root(); - setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); + /* Parse extra opts if any */ + argv=np_extra_opts(&argc, argv, progname); + if(process_arguments(argc,argv)!=OK){ usage4 (_("Could not parse arguments")); } + /* this plugin almost certainly needs root permissions. */ + np_warn_if_not_root(); + /* create socket for DHCP communications */ dhcp_socket=create_dhcp_socket(); /* get hardware address of client machine */ - get_hardware_address(dhcp_socket,network_interface_name); + if(user_specified_mac!=NULL) + memcpy(client_hardware_address,user_specified_mac,6); + else + get_hardware_address(dhcp_socket,network_interface_name); if(unicast) /* get IP address of client machine */ get_ip_address(dhcp_socket,network_interface_name); @@ -308,14 +309,12 @@ int main(int argc, char **argv){ /* determines hardware address on client machine */ int get_hardware_address(int sock,char *interface_name){ - int i; - #if defined(__linux__) struct ifreq ifr; strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1); ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0'; - + /* try and grab hardware address of requested interface */ if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0){ printf(_("Error: Could not get hardware address of interface '%s'\n"),interface_name); @@ -379,7 +378,7 @@ int get_hardware_address(int sock,char *interface_name){ unit = atoi(p) ; *p = '\0' ; strncat(dev, interface_name, 6) ; - } + } else{ printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg lnc0.\n"), interface_name); exit(STATE_UNKNOWN); @@ -404,16 +403,12 @@ int get_hardware_address(int sock,char *interface_name){ /* Kompf 2000-2003 */ #else - printf(_("Error: can't get MAC address for this architecture.\n")); + printf(_("Error: can't get MAC address for this architecture. Use the --mac option.\n")); exit(STATE_UNKNOWN); #endif - if(verbose){ - printf(_("Hardware address: ")); - for (i=0; i<6; ++i) - printf("%2.2x", client_hardware_address[i]); - printf( "\n"); - } + if(verbose) + print_hardware_address(client_hardware_address); return OK; } @@ -509,7 +504,7 @@ int send_dhcp_discover(int sock){ opts += sizeof(requested_address); } discover_packet.options[opts++]=DHCP_OPTION_END; - + /* unicast fields */ if(unicast) discover_packet.giaddr.s_addr = my_ip.s_addr; @@ -536,7 +531,7 @@ int send_dhcp_discover(int sock){ /* send the DHCPDISCOVER packet out */ send_dhcp_packet(&discover_packet,sizeof(discover_packet),sock,&sockaddr_broadcast); - if(verbose) + if(verbose) printf("\n\n"); return OK; @@ -565,7 +560,7 @@ int get_dhcp_offer(int sock){ if((current_time-start_time)>=dhcpoffer_timeout) break; - if(verbose) + if(verbose) printf("\n\n"); bzero(&source,sizeof(source)); @@ -574,7 +569,7 @@ int get_dhcp_offer(int sock){ result=OK; result=receive_dhcp_packet(&offer_packet,sizeof(offer_packet),sock,dhcpoffer_timeout,&source); - + if(result!=OK){ if(verbose) printf(_("Result=ERROR\n")); @@ -582,7 +577,7 @@ int get_dhcp_offer(int sock){ continue; } else{ - if(verbose) + if(verbose) printf(_("Result=OK\n")); responses++; @@ -627,7 +622,7 @@ int get_dhcp_offer(int sock){ printf("\n"); if(result==ERROR){ - if(verbose) + if(verbose) printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n")); continue; @@ -661,7 +656,7 @@ int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in result=sendto(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)dest,sizeof(*dest)); - if(verbose) + if(verbose) printf(_("send_dhcp_packet result: %d\n"),result); if(result<0) @@ -767,7 +762,7 @@ int create_dhcp_socket(void){ } /* set the broadcast option - we need this to listen to DHCP broadcast messages */ - if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&flag,sizeof flag)<0){ + if(!unicast && setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&flag,sizeof flag)<0){ printf(_("Error: Could not set broadcast option on DHCP socket!\n")); exit(STATE_UNKNOWN); } @@ -854,7 +849,7 @@ int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){ /* get option length */ option_length=offer_packet->options[x++]; - if(verbose) + if(verbose) printf("Option: %d (0x%02X)\n",option_type,option_length); /* get option data */ @@ -955,7 +950,7 @@ int free_requested_server_list(void){ next_server=this_server->next; free(this_server); } - + return OK; } @@ -980,7 +975,7 @@ int get_results(void){ /* get max lease time we were offered */ if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) max_lease_time=temp_offer->lease_time; - + /* see if we got the address we requested */ if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) received_requested_address=TRUE; @@ -990,7 +985,7 @@ int get_results(void){ if(verbose){ printf(_("DHCP Server Match: Offerer=%s"),inet_ntoa(temp_offer->server_address)); printf(_(" Requested=%s"),inet_ntoa(temp_server->server_address)); - if(temp_server->answered) + if(temp_server->answered) printf(_(" (duplicate)")); printf(_("\n")); } @@ -1012,7 +1007,7 @@ int get_results(void){ /* get max lease time we were offered */ if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) max_lease_time=temp_offer->lease_time; - + /* see if we got the address we requested */ if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) received_requested_address=TRUE; @@ -1088,15 +1083,15 @@ int process_arguments(int argc, char **argv){ int call_getopt(int argc, char **argv){ int c=0; int i=0; - struct in_addr ipaddress; int option_index = 0; static struct option long_options[] = - { + { {"serverip", required_argument,0,'s'}, {"requestedip", required_argument,0,'r'}, {"timeout", required_argument,0,'t'}, {"interface", required_argument,0,'i'}, + {"mac", required_argument,0,'m'}, {"unicast", no_argument, 0,'u'}, {"verbose", no_argument, 0,'v'}, {"version", no_argument, 0,'V'}, @@ -1105,7 +1100,7 @@ int call_getopt(int argc, char **argv){ }; while(1){ - c=getopt_long(argc,argv,"+hVvt:s:r:t:i:u",long_options,&option_index); + c=getopt_long(argc,argv,"+hVvt:s:r:t:i:m:u",long_options,&option_index); i++; @@ -1126,27 +1121,13 @@ int call_getopt(int argc, char **argv){ switch(c){ case 's': /* DHCP server address */ - if(inet_aton(optarg,&ipaddress)){ - add_requested_server(ipaddress); - inet_aton(optarg, &dhcp_ip); - if (verbose) - printf("querying %s\n",inet_ntoa(dhcp_ip)); - } - /* - else - usage("Invalid server IP address\n"); - */ + resolve_host(optarg,&dhcp_ip); + add_requested_server(dhcp_ip); break; case 'r': /* address we are requested from DHCP servers */ - if(inet_aton(optarg,&ipaddress)){ - requested_address=ipaddress; - request_specific_address=TRUE; - } - /* - else - usage("Invalid requested IP address\n"); - */ + resolve_host(optarg,&requested_address); + request_specific_address=TRUE; break; case 't': /* timeout */ @@ -1162,6 +1143,15 @@ int call_getopt(int argc, char **argv){ */ break; + case 'm': /* MAC address */ + + if((user_specified_mac=mac_aton(optarg)) == NULL) + usage("Cannot parse MAC address.\n"); + if(verbose) + print_hardware_address(user_specified_mac); + + break; + case 'i': /* interface name */ strncpy(network_interface_name,optarg,sizeof(network_interface_name)-1); @@ -1174,7 +1164,7 @@ int call_getopt(int argc, char **argv){ break; case 'V': /* version */ - print_revision(progname,revision); + print_revision(progname, NP_VERSION); exit(STATE_OK); case 'h': /* help */ @@ -1312,7 +1302,7 @@ static int dl_bind(int fd, int sap, u_char *addr){ /*********************************************************************** * interface: - * function mac_addr_dlpi - get the mac address of the interface with + * function mac_addr_dlpi - get the mac address of the interface with * type dev (eg lnc, hme) and unit (0, 1 ..) * * parameter: addr: an array of six bytes, has to be allocated by the caller @@ -1341,23 +1331,71 @@ long mac_addr_dlpi( const char *dev, int unit, u_char *addr){ #endif +/* resolve host name or die (TODO: move this to netutils.c!) */ +void resolve_host(const char *in,struct in_addr *out){ + struct addrinfo hints, *ai; + + memset(&hints,0,sizeof(hints)); + hints.ai_family=PF_INET; + if (getaddrinfo(in,NULL,&hints,&ai) != 0) + usage_va(_("Invalid hostname/address - %s"),optarg); + + memcpy(out,&((struct sockaddr_in *)ai->ai_addr)->sin_addr,sizeof(*out)); + freeaddrinfo(ai); + } + + +/* parse MAC address string, return 6 bytes (unterminated) or NULL */ +unsigned char *mac_aton(const char *string){ + static unsigned char result[6]; + char tmp[3]; + unsigned i, j; + + for(i=0, j=0; string[i] != '\0' && j < sizeof(result); i++){ + /* ignore ':' and any other non-hex character */ + if(!isxdigit(string[i]) || !isxdigit(string[i+1])) + continue; + tmp[0]=string[i]; + tmp[1]=string[i+1]; + tmp[2]='\0'; + result[j]=strtol(tmp,(char **)NULL,16); + i++; + j++; + } + + return (j==6) ? result : NULL; + } + + +void print_hardware_address(const unsigned char *address){ + int i; + + printf(_("Hardware address: ")); + for (i=0; i<5; i++) + printf("%2.2x:", address[i]); + printf("%2.2x", address[i]); + putchar('\n'); + } + + /* print usage help */ void print_help(void){ - print_revision(progname,revision); + print_revision(progname, NP_VERSION); printf("Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n"); printf (COPYRIGHT, copyright, email); - + printf("%s\n", _("This plugin tests the availability of DHCP servers on a network.")); printf ("\n\n"); print_usage(); - printf (_(UT_HELP_VRSN)); + printf (UT_HELP_VRSN); + printf (UT_EXTRA_OPTS); - printf (_(UT_VERBOSE)); + printf (UT_VERBOSE); printf (" %s\n", "-s, --serverip=IPADDRESS"); printf (" %s\n", _("IP address of DHCP server that we must hear from")); @@ -1367,20 +1405,23 @@ void print_help(void){ printf (" %s\n", _("Seconds to wait for DHCPOFFER before timeout occurs")); printf (" %s\n", "-i, --interface=STRING"); printf (" %s\n", _("Interface to to use for listening (i.e. eth0)")); + printf (" %s\n", "-m, --mac=STRING"); + printf (" %s\n", _("MAC address to use in the DHCP request")); printf (" %s\n", "-u, --unicast"); printf (" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s")); + printf (UT_SUPPORT); return; } void print_usage(void){ - - printf (_("Usage:")); + + printf ("%s\n", _("Usage:")); printf (" %s [-v] [-u] [-s serverip] [-r requestedip] [-t timeout]\n",progname); - printf (" [-i interface]\n"); - + printf (" [-i interface] [-m mac]\n"); + return; }