X-Git-Url: https://git.tokkee.org/?p=nagiosplug.git;a=blobdiff_plain;f=plugins-root%2Fcheck_dhcp.c;h=51ac96eab7246b75926ede2e73eff82edf65eecc;hp=fbfb3311b2f4dc3b9270fe71a74c43a576b79036;hb=25d1ee331dbe4977a4a1a756c67f32bd51d9b070;hpb=238b7ae4ea544162e8570fe375c9030b86383577 diff --git a/plugins-root/check_dhcp.c b/plugins-root/check_dhcp.c index fbfb331..51ac96e 100644 --- a/plugins-root/check_dhcp.c +++ b/plugins-root/check_dhcp.c @@ -1,49 +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$ -* +* 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 @@ -59,6 +57,9 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; #include #include #include +#if HAVE_SYS_SOCKIO_H +#include +#endif #if defined( __linux__ ) @@ -74,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 @@ -85,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 @@ -182,8 +183,10 @@ typedef struct requested_server_struct{ #define DHCP_OPTION_BROADCAST_ADDRESS 28 #define DHCP_OPTION_REQUESTED_ADDRESS 50 #define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_SERVER_IDENTIFIER 54 #define DHCP_OPTION_RENEWAL_TIME 58 #define DHCP_OPTION_REBINDING_TIME 59 +#define DHCP_OPTION_END 255 #define DHCP_INFINITE_TIME 0xFFFFFFFF @@ -195,7 +198,11 @@ typedef struct requested_server_struct{ #define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */ #define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */ +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"; @@ -211,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; @@ -226,7 +233,11 @@ 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 *); int send_dhcp_discover(int); int get_dhcp_offer(int); @@ -251,16 +262,28 @@ int main(int argc, char **argv){ 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); /* send DHCPDISCOVER packet */ send_dhcp_discover(dhcp_socket); @@ -286,13 +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)); - + 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); @@ -356,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); @@ -381,25 +403,48 @@ 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; } +/* determines IP address of the client interface */ +int get_ip_address(int sock,char *interface_name){ +#if defined(SIOCGIFADDR) + struct ifreq ifr; + + strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0'; + + if(ioctl(sock,SIOCGIFADDR,&ifr)<0){ + printf(_("Error: Cannot determine IP address of interface %s\n"), + interface_name); + exit(STATE_UNKNOWN); + } + + my_ip=((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; + +#else + printf(_("Error: Cannot get interface IP address on this platform.\n")); + exit(STATE_UNKNOWN); +#endif + + if(verbose) + printf(_("Pretending to be relay client %s\n"),inet_ntoa(my_ip)); + + return OK; + } /* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ int send_dhcp_discover(int sock){ dhcp_packet discover_packet; struct sockaddr_in sockaddr_broadcast; + unsigned short opts; /* clear the packet data structure */ @@ -415,9 +460,10 @@ int send_dhcp_discover(int sock){ /* length of our hardware address */ discover_packet.hlen=ETHERNET_HARDWARE_ADDRESS_LENGTH; - discover_packet.hops=0; - - /* transaction id is supposed to be random */ + /* + * transaction ID is supposed to be random. We won't use the address so + * we don't care about high entropy here. time(2) is good enough. + */ srand(time(NULL)); packet_xid=random(); discover_packet.xid=htonl(packet_xid); @@ -429,8 +475,11 @@ int send_dhcp_discover(int sock){ /*discover_packet.secs=htons(65535);*/ discover_packet.secs=0xFF; - /* tell server it should broadcast its response */ - discover_packet.flags=htons(DHCP_BROADCAST_FLAG); + /* + * server needs to know if it should broadcast or unicast its response: + * 0x8000L == 32768 == 1 << 15 == broadcast, 0 == unicast + */ + discover_packet.flags = unicast ? 0 : htons(DHCP_BROADCAST_FLAG); /* our hardware address */ memcpy(discover_packet.chaddr,client_hardware_address,ETHERNET_HARDWARE_ADDRESS_LENGTH); @@ -441,28 +490,38 @@ int send_dhcp_discover(int sock){ discover_packet.options[2]='\x53'; discover_packet.options[3]='\x63'; + opts = 4; /* DHCP message type is embedded in options field */ - discover_packet.options[4]=DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ - discover_packet.options[5]='\x01'; /* DHCP message option length in bytes */ - discover_packet.options[6]=DHCPDISCOVER; + discover_packet.options[opts++]=DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ + discover_packet.options[opts++]='\x01'; /* DHCP message option length in bytes */ + discover_packet.options[opts++]=DHCPDISCOVER; /* the IP address we're requesting */ if(request_specific_address==TRUE){ - discover_packet.options[7]=DHCP_OPTION_REQUESTED_ADDRESS; - discover_packet.options[8]='\x04'; - memcpy(&discover_packet.options[9],&requested_address,sizeof(requested_address)); + discover_packet.options[opts++]=DHCP_OPTION_REQUESTED_ADDRESS; + discover_packet.options[opts++]='\x04'; + memcpy(&discover_packet.options[opts],&requested_address,sizeof(requested_address)); + opts += sizeof(requested_address); } - + discover_packet.options[opts++]=DHCP_OPTION_END; + + /* unicast fields */ + if(unicast) + discover_packet.giaddr.s_addr = my_ip.s_addr; + + /* see RFC 1542, 4.1.1 */ + discover_packet.hops = unicast ? 1 : 0; + /* send the DHCPDISCOVER packet to broadcast address */ sockaddr_broadcast.sin_family=AF_INET; sockaddr_broadcast.sin_port=htons(DHCP_SERVER_PORT); - sockaddr_broadcast.sin_addr.s_addr=INADDR_BROADCAST; + sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST; bzero(&sockaddr_broadcast.sin_zero,sizeof(sockaddr_broadcast.sin_zero)); if(verbose){ printf(_("DHCPDISCOVER to %s port %d\n"),inet_ntoa(sockaddr_broadcast.sin_addr),ntohs(sockaddr_broadcast.sin_port)); - printf("DHCPDISCOVER XID: %lu (0x%X)\n",ntohl(discover_packet.xid),ntohl(discover_packet.xid)); + printf("DHCPDISCOVER XID: %u (0x%X)\n",ntohl(discover_packet.xid),ntohl(discover_packet.xid)); printf("DHCDISCOVER ciaddr: %s\n",inet_ntoa(discover_packet.ciaddr)); printf("DHCDISCOVER yiaddr: %s\n",inet_ntoa(discover_packet.yiaddr)); printf("DHCDISCOVER siaddr: %s\n",inet_ntoa(discover_packet.siaddr)); @@ -472,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; @@ -487,7 +546,6 @@ int get_dhcp_offer(int sock){ struct sockaddr_in source; struct sockaddr_in via; int result=OK; - int timeout=1; int responses=0; int x; time_t start_time; @@ -502,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)); @@ -511,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")); @@ -519,7 +577,7 @@ int get_dhcp_offer(int sock){ continue; } else{ - if(verbose) + if(verbose) printf(_("Result=OK\n")); responses++; @@ -537,13 +595,13 @@ int get_dhcp_offer(int sock){ if(verbose){ printf(_("DHCPOFFER from IP address %s"),inet_ntoa(source.sin_addr)); printf(_(" via %s\n"),inet_ntoa(via.sin_addr)); - printf("DHCPOFFER XID: %lu (0x%X)\n",ntohl(offer_packet.xid),ntohl(offer_packet.xid)); + printf("DHCPOFFER XID: %u (0x%X)\n",ntohl(offer_packet.xid),ntohl(offer_packet.xid)); } /* check packet xid to see if its the same as the one we used in the discover packet */ if(ntohl(offer_packet.xid)!=packet_xid){ if(verbose) - printf(_("DHCPOFFER XID (%lu) did not match DHCPDISCOVER XID (%lu) - ignoring packet\n"),ntohl(offer_packet.xid),packet_xid); + printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"),ntohl(offer_packet.xid),packet_xid); continue; } @@ -564,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; @@ -594,12 +652,11 @@ int get_dhcp_offer(int sock){ /* sends a DHCP packet */ int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest){ - struct sockaddr_in myname; int result; 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) @@ -614,22 +671,26 @@ int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address){ struct timeval tv; fd_set readfds; + fd_set oobfds; int recv_result; socklen_t address_size; struct sockaddr_in source_address; + int nfound; /* wait for data to arrive (up time timeout) */ tv.tv_sec=timeout; tv.tv_usec=0; FD_ZERO(&readfds); + FD_ZERO(&oobfds); FD_SET(sock,&readfds); - select(sock+1,&readfds,NULL,NULL,&tv); + FD_SET(sock,&oobfds); + nfound = select(sock+1,&readfds,NULL,&oobfds,&tv); /* make sure some data has arrived */ if(!FD_ISSET(sock,&readfds)){ if(verbose) - printf(_("No (more) data received\n")); + printf(_("No (more) data received (nfound: %d)\n"), nfound); return ERROR; } @@ -678,8 +739,9 @@ int create_dhcp_socket(void){ /* Set up the address we're going to bind to. */ bzero(&myname,sizeof(myname)); myname.sin_family=AF_INET; - myname.sin_port=htons(DHCP_CLIENT_PORT); - myname.sin_addr.s_addr=INADDR_ANY; /* listen on any address */ + /* listen to DHCP server port if we're in unicast mode */ + myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT); + myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY; bzero(&myname.sin_zero,sizeof(myname.sin_zero)); /* create a socket for DHCP communications */ @@ -700,21 +762,23 @@ 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); } /* bind socket to interface */ #if defined(__linux__) - strncpy(interface.ifr_ifrn.ifrn_name,network_interface_name,IFNAMSIZ); + strncpy(interface.ifr_ifrn.ifrn_name,network_interface_name,IFNAMSIZ-1); + interface.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0'; if(setsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,(char *)&interface,sizeof(interface))<0){ printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"),network_interface_name); exit(STATE_UNKNOWN); } #else - strncpy(interface.ifr_name,network_interface_name,IFNAMSIZ); + strncpy(interface.ifr_name,network_interface_name,IFNAMSIZ-1); + interface.ifr_name[IFNAMSIZ-1]='\0'; #endif /* bind the socket */ @@ -765,9 +829,9 @@ int add_requested_server(struct in_addr server_address){ int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){ dhcp_offer *new_offer; int x; - int y; unsigned option_type; unsigned option_length; + struct in_addr serv_ident = {0}; if(offer_packet==NULL) return ERROR; @@ -785,27 +849,32 @@ 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 */ - if(option_type==DHCP_OPTION_LEASE_TIME){ + switch(option_type){ + case DHCP_OPTION_LEASE_TIME: memcpy(&dhcp_lease_time, &offer_packet->options[x],sizeof(dhcp_lease_time)); dhcp_lease_time = ntohl(dhcp_lease_time); - } - if(option_type==DHCP_OPTION_RENEWAL_TIME){ + break; + case DHCP_OPTION_RENEWAL_TIME: memcpy(&dhcp_renewal_time, &offer_packet->options[x],sizeof(dhcp_renewal_time)); dhcp_renewal_time = ntohl(dhcp_renewal_time); - } - if(option_type==DHCP_OPTION_REBINDING_TIME){ + break; + case DHCP_OPTION_REBINDING_TIME: memcpy(&dhcp_rebinding_time, &offer_packet->options[x],sizeof(dhcp_rebinding_time)); dhcp_rebinding_time = ntohl(dhcp_rebinding_time); + break; + case DHCP_OPTION_SERVER_IDENTIFIER: + memcpy(&serv_ident.s_addr, &offer_packet->options[x],sizeof(serv_ident.s_addr)); + break; } /* skip option data we're ignoring */ - else - for(y=0;yserver_address=source; + /* + * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the + * 'siaddr' field as the address of the server to use in the next step + * of the client's bootstrap process. A DHCP server may return its own + * address in the 'siaddr' field, if the server is prepared to supply + * the next bootstrap service (e.g., delivery of an operating system + * executable image). A DHCP server always returns its own address in + * the 'server identifier' option." 'serv_ident' is the 'server + * identifier' option, 'source' is the 'siaddr' field or (if 'siaddr' + * wasn't available) the IP address we received the DHCPOFFER from. If + * 'serv_ident' isn't available for some reason, we use 'source'. + */ + new_offer->server_address=serv_ident.s_addr?serv_ident:source; new_offer->offered_address=offer_packet->yiaddr; new_offer->lease_time=dhcp_lease_time; new_offer->renewal_time=dhcp_renewal_time; @@ -869,7 +950,7 @@ int free_requested_server_list(void){ next_server=this_server->next; free(this_server); } - + return OK; } @@ -894,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; @@ -904,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")); } @@ -926,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; @@ -1002,15 +1083,16 @@ 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'}, {"help", no_argument, 0,'h'}, @@ -1018,7 +1100,7 @@ int call_getopt(int argc, char **argv){ }; while(1){ - c=getopt_long(argc,argv,"+hVvt:s:r:t:i:",long_options,&option_index); + c=getopt_long(argc,argv,"+hVvt:s:r:t:i:m:u",long_options,&option_index); i++; @@ -1039,23 +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); - /* - 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 */ @@ -1071,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); @@ -1078,8 +1159,12 @@ int call_getopt(int argc, char **argv){ break; + case 'u': /* unicast testing */ + unicast=1; + break; + case 'V': /* version */ - print_revision(progname,revision); + print_revision(progname, NP_VERSION); exit(STATE_OK); case 'h': /* help */ @@ -1091,7 +1176,7 @@ int call_getopt(int argc, char **argv){ break; case '?': /* help */ - usage2 (_("Unknown argument"), optarg); + usage5 (); break; default: @@ -1217,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 @@ -1246,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")); @@ -1272,17 +1405,29 @@ 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")); + +#ifdef NP_EXTRA_OPTS + printf ("\n"); + printf ("%s\n", _("Notes:")); + printf (UT_EXTRA_OPTS_NOTES); +#endif + printf (UT_SUPPORT); return; } void print_usage(void){ - + printf (_("Usage:")); - printf ("%s [-s serverip] [-r requestedip] [-t timeout] [-i interface] [-v]\n",progname); - + printf (" %s [-v] [-u] [-s serverip] [-r requestedip] [-t timeout]\n",progname); + printf (" [-i interface] [-m mac]\n"); + return; }