check_dhcp.c 34 KB

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