summaryrefslogtreecommitdiffstats
path: root/plugins-root
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root')
-rw-r--r--plugins-root/check_dhcp.c84
1 files changed, 74 insertions, 10 deletions
diff --git a/plugins-root/check_dhcp.c b/plugins-root/check_dhcp.c
index 7cb2d300..a1d04c18 100644
--- a/plugins-root/check_dhcp.c
+++ b/plugins-root/check_dhcp.c
@@ -33,6 +33,12 @@
33* 33*
34* $Id$ 34* $Id$
35* 35*
36* ------------------------------------------------------------------------
37* Unicast mode was originally implemented by Heiti of Boras Kommun with
38* general improvements as well as usability fixes and "forward"-porting by
39* Andreas Ericsson of OP5 AB.
40* ------------------------------------------------------------------------
41*
36*****************************************************************************/ 42*****************************************************************************/
37 43
38const char *progname = "check_dhcp"; 44const char *progname = "check_dhcp";
@@ -59,6 +65,9 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
59#include <netinet/in.h> 65#include <netinet/in.h>
60#include <net/if.h> 66#include <net/if.h>
61#include <arpa/inet.h> 67#include <arpa/inet.h>
68#if HAVE_SYS_SOCKIO_H
69#include <sys/sockio.h>
70#endif
62 71
63#if defined( __linux__ ) 72#if defined( __linux__ )
64 73
@@ -190,6 +199,7 @@ typedef struct requested_server_struct{
190#define DHCP_INFINITE_TIME 0xFFFFFFFF 199#define DHCP_INFINITE_TIME 0xFFFFFFFF
191 200
192#define DHCP_BROADCAST_FLAG 32768 201#define DHCP_BROADCAST_FLAG 32768
202#define DHCP_UNICAST_FLAG 0
193 203
194#define DHCP_SERVER_PORT 67 204#define DHCP_SERVER_PORT 67
195#define DHCP_CLIENT_PORT 68 205#define DHCP_CLIENT_PORT 68
@@ -197,6 +207,9 @@ typedef struct requested_server_struct{
197#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */ 207#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */
198#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */ 208#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */
199 209
210u_int8_t unicast = 0; /* unicast mode: mimic a DHCP relay */
211struct in_addr my_ip; /* our address (required for relay) */
212struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
200unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]=""; 213unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]="";
201 214
202char network_interface_name[IFNAMSIZ]="eth0"; 215char network_interface_name[IFNAMSIZ]="eth0";
@@ -229,6 +242,7 @@ void print_usage(void);
229void print_help(void); 242void print_help(void);
230 243
231int get_hardware_address(int,char *); 244int get_hardware_address(int,char *);
245int get_ip_address(int,char *);
232 246
233int send_dhcp_discover(int); 247int send_dhcp_discover(int);
234int get_dhcp_offer(int); 248int get_dhcp_offer(int);
@@ -267,6 +281,9 @@ int main(int argc, char **argv){
267 /* get hardware address of client machine */ 281 /* get hardware address of client machine */
268 get_hardware_address(dhcp_socket,network_interface_name); 282 get_hardware_address(dhcp_socket,network_interface_name);
269 283
284 if(unicast) /* get IP address of client machine */
285 get_ip_address(dhcp_socket,network_interface_name);
286
270 /* send DHCPDISCOVER packet */ 287 /* send DHCPDISCOVER packet */
271 send_dhcp_discover(dhcp_socket); 288 send_dhcp_discover(dhcp_socket);
272 289
@@ -400,6 +417,32 @@ int get_hardware_address(int sock,char *interface_name){
400 return OK; 417 return OK;
401 } 418 }
402 419
420/* determines IP address of the client interface */
421int get_ip_address(int sock,char *interface_name){
422#if defined(SIOCGIFADDR)
423 struct ifreq ifr;
424
425 strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1);
426 ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0';
427
428 if(ioctl(sock,SIOCGIFADDR,&ifr)<0){
429 printf(_("Error: Cannot determine IP address of interface %s\n"),
430 interface_name);
431 exit(STATE_UNKNOWN);
432 }
433
434 my_ip=((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
435
436#else
437 printf(_("Error: Cannot get interface IP address on this platform.\n"));
438 exit(STATE_UNKNOWN);
439#endif
440
441 if(verbose)
442 printf(_("Pretending to be relay client %s\n"),inet_ntoa(my_ip));
443
444 return OK;
445 }
403 446
404/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 447/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */
405int send_dhcp_discover(int sock){ 448int send_dhcp_discover(int sock){
@@ -421,8 +464,6 @@ int send_dhcp_discover(int sock){
421 /* length of our hardware address */ 464 /* length of our hardware address */
422 discover_packet.hlen=ETHERNET_HARDWARE_ADDRESS_LENGTH; 465 discover_packet.hlen=ETHERNET_HARDWARE_ADDRESS_LENGTH;
423 466
424 discover_packet.hops=0;
425
426 /* transaction id is supposed to be random */ 467 /* transaction id is supposed to be random */
427 srand(time(NULL)); 468 srand(time(NULL));
428 packet_xid=random(); 469 packet_xid=random();
@@ -435,8 +476,11 @@ int send_dhcp_discover(int sock){
435 /*discover_packet.secs=htons(65535);*/ 476 /*discover_packet.secs=htons(65535);*/
436 discover_packet.secs=0xFF; 477 discover_packet.secs=0xFF;
437 478
438 /* tell server it should broadcast its response */ 479 /*
439 discover_packet.flags=htons(DHCP_BROADCAST_FLAG); 480 * server needs to know if it should broadcast or unicast its response:
481 * 0x8000L == 32768 == 1 << 15 == broadcast, 0 == unicast
482 */
483 discover_packet.flags = unicast ? 0 : htons(DHCP_BROADCAST_FLAG);
440 484
441 /* our hardware address */ 485 /* our hardware address */
442 memcpy(discover_packet.chaddr,client_hardware_address,ETHERNET_HARDWARE_ADDRESS_LENGTH); 486 memcpy(discover_packet.chaddr,client_hardware_address,ETHERNET_HARDWARE_ADDRESS_LENGTH);
@@ -462,10 +506,17 @@ int send_dhcp_discover(int sock){
462 } 506 }
463 discover_packet.options[opts++]=DHCP_OPTION_END; 507 discover_packet.options[opts++]=DHCP_OPTION_END;
464 508
509 /* unicast fields */
510 if(unicast)
511 discover_packet.giaddr.s_addr = my_ip.s_addr;
512
513 /* see RFC 1542, 4.1.1 */
514 discover_packet.hops = unicast ? 1 : 0;
515
465 /* send the DHCPDISCOVER packet to broadcast address */ 516 /* send the DHCPDISCOVER packet to broadcast address */
466 sockaddr_broadcast.sin_family=AF_INET; 517 sockaddr_broadcast.sin_family=AF_INET;
467 sockaddr_broadcast.sin_port=htons(DHCP_SERVER_PORT); 518 sockaddr_broadcast.sin_port=htons(DHCP_SERVER_PORT);
468 sockaddr_broadcast.sin_addr.s_addr=INADDR_BROADCAST; 519 sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST;
469 bzero(&sockaddr_broadcast.sin_zero,sizeof(sockaddr_broadcast.sin_zero)); 520 bzero(&sockaddr_broadcast.sin_zero,sizeof(sockaddr_broadcast.sin_zero));
470 521
471 522
@@ -685,8 +736,9 @@ int create_dhcp_socket(void){
685 /* Set up the address we're going to bind to. */ 736 /* Set up the address we're going to bind to. */
686 bzero(&myname,sizeof(myname)); 737 bzero(&myname,sizeof(myname));
687 myname.sin_family=AF_INET; 738 myname.sin_family=AF_INET;
688 myname.sin_port=htons(DHCP_CLIENT_PORT); 739 /* listen to DHCP server port if we're in unicast mode */
689 myname.sin_addr.s_addr=INADDR_ANY; /* listen on any address */ 740 myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT);
741 myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY;
690 bzero(&myname.sin_zero,sizeof(myname.sin_zero)); 742 bzero(&myname.sin_zero,sizeof(myname.sin_zero));
691 743
692 /* create a socket for DHCP communications */ 744 /* create a socket for DHCP communications */
@@ -1035,6 +1087,7 @@ int call_getopt(int argc, char **argv){
1035 {"requestedip", required_argument,0,'r'}, 1087 {"requestedip", required_argument,0,'r'},
1036 {"timeout", required_argument,0,'t'}, 1088 {"timeout", required_argument,0,'t'},
1037 {"interface", required_argument,0,'i'}, 1089 {"interface", required_argument,0,'i'},
1090 {"unicast", no_argument, 0,'u'},
1038 {"verbose", no_argument, 0,'v'}, 1091 {"verbose", no_argument, 0,'v'},
1039 {"version", no_argument, 0,'V'}, 1092 {"version", no_argument, 0,'V'},
1040 {"help", no_argument, 0,'h'}, 1093 {"help", no_argument, 0,'h'},
@@ -1042,7 +1095,7 @@ int call_getopt(int argc, char **argv){
1042 }; 1095 };
1043 1096
1044 while(1){ 1097 while(1){
1045 c=getopt_long(argc,argv,"+hVvt:s:r:t:i:",long_options,&option_index); 1098 c=getopt_long(argc,argv,"+hVvt:s:r:t:i:u",long_options,&option_index);
1046 1099
1047 i++; 1100 i++;
1048 1101
@@ -1063,8 +1116,12 @@ int call_getopt(int argc, char **argv){
1063 switch(c){ 1116 switch(c){
1064 1117
1065 case 's': /* DHCP server address */ 1118 case 's': /* DHCP server address */
1066 if(inet_aton(optarg,&ipaddress)) 1119 if(inet_aton(optarg,&ipaddress)){
1067 add_requested_server(ipaddress); 1120 add_requested_server(ipaddress);
1121 inet_aton(optarg, &dhcp_ip);
1122 if (verbose)
1123 printf("querying %s\n",inet_ntoa(dhcp_ip));
1124 }
1068 /* 1125 /*
1069 else 1126 else
1070 usage("Invalid server IP address\n"); 1127 usage("Invalid server IP address\n");
@@ -1102,6 +1159,10 @@ int call_getopt(int argc, char **argv){
1102 1159
1103 break; 1160 break;
1104 1161
1162 case 'u': /* unicast testing */
1163 unicast=1;
1164 break;
1165
1105 case 'V': /* version */ 1166 case 'V': /* version */
1106 print_revision(progname,revision); 1167 print_revision(progname,revision);
1107 exit(STATE_OK); 1168 exit(STATE_OK);
@@ -1296,6 +1357,8 @@ void print_help(void){
1296 printf (" %s\n", _("Seconds to wait for DHCPOFFER before timeout occurs")); 1357 printf (" %s\n", _("Seconds to wait for DHCPOFFER before timeout occurs"));
1297 printf (" %s\n", "-i, --interface=STRING"); 1358 printf (" %s\n", "-i, --interface=STRING");
1298 printf (" %s\n", _("Interface to to use for listening (i.e. eth0)")); 1359 printf (" %s\n", _("Interface to to use for listening (i.e. eth0)"));
1360 printf (" %s\n", "-u, --unicast");
1361 printf (" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s"));
1299 1362
1300 return; 1363 return;
1301 } 1364 }
@@ -1305,7 +1368,8 @@ void
1305print_usage(void){ 1368print_usage(void){
1306 1369
1307 printf (_("Usage:")); 1370 printf (_("Usage:"));
1308 printf ("%s [-s serverip] [-r requestedip] [-t timeout] [-i interface] [-v]\n",progname); 1371 printf (" %s [-v] [-u] [-s serverip] [-r requestedip] [-t timeout]\n",progname);
1372 printf (" [-i interface]\n");
1309 1373
1310 return; 1374 return;
1311 } 1375 }