diff options
| -rw-r--r-- | NEWS | 2 | ||||
| -rw-r--r-- | THANKS.in | 1 | ||||
| -rw-r--r-- | configure.in | 3 | ||||
| -rw-r--r-- | plugins-root/check_dhcp.c | 84 |
4 files changed, 80 insertions, 10 deletions
| @@ -9,6 +9,8 @@ This file documents the major additions and syntax changes between releases. | |||
| 9 | Check_disk now calls stat() on all filesystems to check. (Old: only the ones selected using -p) | 9 | Check_disk now calls stat() on all filesystems to check. (Old: only the ones selected using -p) |
| 10 | A meaningful error message (eg "Stale NFS Handle") is printed if stat fails. | 10 | A meaningful error message (eg "Stale NFS Handle") is printed if stat fails. |
| 11 | Check_disk's --help now prints some examples for the new features introduced in 1.4.8 | 11 | Check_disk's --help now prints some examples for the new features introduced in 1.4.8 |
| 12 | New check_dhcp -u/--unicast option for emulating a DHCP relay in order | ||
| 13 | to check DHCP servers on remote networks | ||
| 12 | 14 | ||
| 13 | 1.4.9 4th June 2006 | 15 | 1.4.9 4th June 2006 |
| 14 | Inclusion of contrib/check_cluster2 as check_cluster with some improvements | 16 | Inclusion of contrib/check_cluster2 as check_cluster with some improvements |
| @@ -223,3 +223,4 @@ Daniel Bimschas | |||
| 223 | Aurelien Bompard | 223 | Aurelien Bompard |
| 224 | Christoph Schell | 224 | Christoph Schell |
| 225 | Andrew Elwell | 225 | Andrew Elwell |
| 226 | Heiti Ernits | ||
diff --git a/configure.in b/configure.in index 5b5b983b..86f37809 100644 --- a/configure.in +++ b/configure.in | |||
| @@ -1450,6 +1450,9 @@ elif test -f ../plugins/check_nt.c ; then | |||
| 1450 | fi | 1450 | fi |
| 1451 | 1451 | ||
| 1452 | 1452 | ||
| 1453 | dnl used in check_dhcp | ||
| 1454 | AC_CHECK_HEADERS(sys/sockio.h) | ||
| 1455 | |||
| 1453 | case $host in | 1456 | case $host in |
| 1454 | *bsd*) | 1457 | *bsd*) |
| 1455 | AC_DEFINE(__bsd__,1,[bsd specific code in check_dhcp.c]) | 1458 | AC_DEFINE(__bsd__,1,[bsd specific code in check_dhcp.c]) |
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 | ||
| 38 | const char *progname = "check_dhcp"; | 44 | const 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 | ||
| 210 | u_int8_t unicast = 0; /* unicast mode: mimic a DHCP relay */ | ||
| 211 | struct in_addr my_ip; /* our address (required for relay) */ | ||
| 212 | struct in_addr dhcp_ip; /* server to query (if in unicast mode) */ | ||
| 200 | unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]=""; | 213 | unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]=""; |
| 201 | 214 | ||
| 202 | char network_interface_name[IFNAMSIZ]="eth0"; | 215 | char network_interface_name[IFNAMSIZ]="eth0"; |
| @@ -229,6 +242,7 @@ void print_usage(void); | |||
| 229 | void print_help(void); | 242 | void print_help(void); |
| 230 | 243 | ||
| 231 | int get_hardware_address(int,char *); | 244 | int get_hardware_address(int,char *); |
| 245 | int get_ip_address(int,char *); | ||
| 232 | 246 | ||
| 233 | int send_dhcp_discover(int); | 247 | int send_dhcp_discover(int); |
| 234 | int get_dhcp_offer(int); | 248 | int 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 */ | ||
| 421 | int 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 */ |
| 405 | int send_dhcp_discover(int sock){ | 448 | int 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 | |||
| 1305 | print_usage(void){ | 1368 | print_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 | } |
