D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
usr
/
src
/
nrpe-2.15
/
src
/
Filename :
check_nrpe.c
back
Copy
/******************************************************************************************** * * CHECK_NRPE.C - NRPE Plugin For Nagios * Copyright (c) 1999-2008 Ethan Galstad (nagios@nagios.org) * License: GPL * * Last Modified: 09-06-2013 * * Command line: CHECK_NRPE -H <host_address> [-p port] [-c command] [-to to_sec] * * Description: * * This plugin will attempt to connect to the NRPE daemon on the specified server and port. * The daemon will attempt to run the command defined as [command]. Program output and * return code are sent back from the daemon and displayed as this plugin's own output and * return code. * ********************************************************************************************/ #include "config.h" #include "common.h" #include "utils.h" #define DEFAULT_NRPE_COMMAND "_NRPE_CHECK" /* check version of NRPE daemon */ u_short server_port=DEFAULT_SERVER_PORT; char *server_name=NULL; char *bind_address=NULL; struct sockaddr_storage hostaddr; int address_family=AF_UNSPEC; char *command_name=NULL; int socket_timeout=DEFAULT_SOCKET_TIMEOUT; int timeout_return_code=STATE_CRITICAL; int sd; char query[MAX_INPUT_BUFFER]=""; int show_help=FALSE; int show_license=FALSE; int show_version=FALSE; #ifdef HAVE_SSL #ifdef __sun SSL_METHOD *meth; #else const SSL_METHOD *meth; #endif SSL_CTX *ctx; SSL *ssl; int use_ssl=TRUE; #else int use_ssl=FALSE; #endif int process_arguments(int,char **); void alarm_handler(int); int graceful_close(int,int); int main(int argc, char **argv){ u_int32_t packet_crc32; u_int32_t calculated_crc32; int16_t result; int rc; packet send_packet; packet receive_packet; int bytes_to_send; int bytes_to_recv; result=process_arguments(argc,argv); if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){ if(result!=OK) printf("Incorrect command line arguments supplied\n"); printf("\n"); printf("NRPE Plugin for Nagios\n"); printf("Copyright (c) 1999-2008 Ethan Galstad (nagios@nagios.org)\n"); printf("Version: %s\n",PROGRAM_VERSION); printf("Last Modified: %s\n",MODIFICATION_DATE); printf("License: GPL v2 with exemptions (-l for more info)\n"); #ifdef HAVE_SSL printf("SSL/TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required\n"); #endif printf("\n"); } if(result!=OK || show_help==TRUE){ printf("Usage: check_nrpe -H <host> [ -b <bindaddr> ] [-4] [-6] [-n] [-u] [-p <port>] [-t <timeout>] [-c <command>] [-a <arglist...>]\n"); printf("\n"); printf("Options:\n"); printf(" -n = Do no use SSL\n"); printf(" -u = Make socket timeouts return an UNKNOWN state instead of CRITICAL\n"); printf(" <host> = The address of the host running the NRPE daemon\n"); printf(" <bindaddr> = bind to local address\n"); printf(" -4 = user ipv4 only\n"); printf(" -6 = user ipv6 only\n"); printf(" [port] = The port on which the daemon is running (default=%d)\n",DEFAULT_SERVER_PORT); printf(" [timeout] = Number of seconds before connection times out (default=%d)\n",DEFAULT_SOCKET_TIMEOUT); printf(" [command] = The name of the command that the remote daemon should run\n"); printf(" [arglist] = Optional arguments that should be passed to the command. Multiple\n"); printf(" arguments should be separated by a space. If provided, this must be\n"); printf(" the last option supplied on the command line.\n"); printf("\n"); printf("Note:\n"); printf("This plugin requires that you have the NRPE daemon running on the remote host.\n"); printf("You must also have configured the daemon to associate a specific plugin command\n"); printf("with the [command] option you are specifying here. Upon receipt of the\n"); printf("[command] argument, the NRPE daemon will run the appropriate plugin command and\n"); printf("send the plugin output and return code back to *this* plugin. This allows you\n"); printf("to execute plugins on remote hosts and 'fake' the results to make Nagios think\n"); printf("the plugin is being run locally.\n"); printf("\n"); } if(show_license==TRUE) display_license(); if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE) exit(STATE_UNKNOWN); /* generate the CRC 32 table */ generate_crc32_table(); #ifdef HAVE_SSL /* initialize SSL */ if(use_ssl==TRUE){ SSL_library_init(); SSLeay_add_ssl_algorithms(); meth=SSLv23_client_method(); SSL_load_error_strings(); if((ctx=SSL_CTX_new(meth))==NULL){ printf("CHECK_NRPE: Error - could not create SSL context.\n"); exit(STATE_CRITICAL); } /* ADDED 01/19/2004 */ /* use only TLSv1 protocol */ SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); } #endif /* initialize alarm signal handling */ signal(SIGALRM,alarm_handler); /* set socket timeout */ alarm(socket_timeout); /* try to connect to the host at the given port number */ if((sd=my_connect(server_name, &hostaddr, server_port, address_family, bind_address)) < 0 ) { exit (255); } else { result=STATE_OK; } #ifdef HAVE_SSL /* do SSL handshake */ if(result==STATE_OK && use_ssl==TRUE){ if((ssl=SSL_new(ctx))!=NULL){ SSL_CTX_set_cipher_list(ctx,"ADH"); SSL_set_fd(ssl,sd); if((rc=SSL_connect(ssl))!=1){ printf("CHECK_NRPE: Error - Could not complete SSL handshake.\n"); #ifdef DEBUG printf("SSL_connect=%d\n",rc); /* rc=SSL_get_error(ssl,rc); printf("SSL_get_error=%d\n",rc); printf("ERR_get_error=%lu\n",ERR_get_error()); printf("%s\n",ERR_error_string(rc,NULL)); */ ERR_print_errors_fp(stdout); #endif result=STATE_CRITICAL; } } else{ printf("CHECK_NRPE: Error - Could not create SSL connection structure.\n"); result=STATE_CRITICAL; } /* bail if we had errors */ if(result!=STATE_OK){ SSL_CTX_free(ctx); close(sd); exit(result); } } #endif /* we're connected and ready to go */ if(result==STATE_OK){ /* clear the packet buffer */ bzero(&send_packet,sizeof(send_packet)); /* fill the packet with semi-random data */ randomize_buffer((char *)&send_packet,sizeof(send_packet)); /* initialize packet data */ send_packet.packet_version=(int16_t)htons(NRPE_PACKET_VERSION_2); send_packet.packet_type=(int16_t)htons(QUERY_PACKET); strncpy(&send_packet.buffer[0],query,MAX_PACKETBUFFER_LENGTH); send_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0'; /* calculate the crc 32 value of the packet */ send_packet.crc32_value=(u_int32_t)0L; calculated_crc32=calculate_crc32((char *)&send_packet,sizeof(send_packet)); send_packet.crc32_value=(u_int32_t)htonl(calculated_crc32); /***** ENCRYPT REQUEST *****/ /* send the packet */ bytes_to_send=sizeof(send_packet); if(use_ssl==FALSE) rc=sendall(sd,(char *)&send_packet,&bytes_to_send); #ifdef HAVE_SSL else{ rc=SSL_write(ssl,&send_packet,bytes_to_send); if(rc<0) rc=-1; } #endif if(rc==-1){ printf("CHECK_NRPE: Error sending query to host.\n"); close(sd); return STATE_UNKNOWN; } /* wait for the response packet */ bytes_to_recv=sizeof(receive_packet); if(use_ssl==FALSE) rc=recvall(sd,(char *)&receive_packet,&bytes_to_recv,socket_timeout); #ifdef HAVE_SSL else rc=SSL_read(ssl,&receive_packet,bytes_to_recv); #endif /* reset timeout */ alarm(0); /* close the connection */ #ifdef HAVE_SSL if(use_ssl==TRUE){ SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); } #endif graceful_close(sd,1000); /* recv() error */ if(rc<0){ printf("CHECK_NRPE: Error receiving data from daemon.\n"); return STATE_UNKNOWN; } /* server disconnected */ else if(rc==0){ printf("CHECK_NRPE: Received 0 bytes from daemon. Check the remote server logs for error messages.\n"); return STATE_UNKNOWN; } /* receive underflow */ else if(bytes_to_recv<sizeof(receive_packet)){ printf("CHECK_NRPE: Receive underflow - only %d bytes received (%d expected).\n",bytes_to_recv,sizeof(receive_packet)); return STATE_UNKNOWN; } /***** DECRYPT RESPONSE *****/ /* check the crc 32 value */ packet_crc32=ntohl(receive_packet.crc32_value); receive_packet.crc32_value=0L; calculated_crc32=calculate_crc32((char *)&receive_packet,sizeof(receive_packet)); if(packet_crc32!=calculated_crc32){ printf("CHECK_NRPE: Response packet had invalid CRC32.\n"); close(sd); return STATE_UNKNOWN; } /* check packet version */ if(ntohs(receive_packet.packet_version)!=NRPE_PACKET_VERSION_2){ printf("CHECK_NRPE: Invalid packet version received from server.\n"); close(sd); return STATE_UNKNOWN; } /* check packet type */ if(ntohs(receive_packet.packet_type)!=RESPONSE_PACKET){ printf("CHECK_NRPE: Invalid packet type received from server.\n"); close(sd); return STATE_UNKNOWN; } /* get the return code from the remote plugin */ result=(int16_t)ntohs(receive_packet.result_code); /* print the output returned by the daemon */ receive_packet.buffer[MAX_PACKETBUFFER_LENGTH-1]='\x0'; if(!strcmp(receive_packet.buffer,"")) printf("CHECK_NRPE: No output returned from daemon.\n"); else printf("%s\n",receive_packet.buffer); } /* reset the alarm */ else alarm(0); return result; } /* process command line arguments */ int process_arguments(int argc, char **argv){ char optchars[MAX_INPUT_BUFFER]; int argindex=0; int c=1; int i=1; #ifdef HAVE_GETOPT_LONG int option_index=0; static struct option long_options[]={ {"host", required_argument, 0, 'H'}, {"bind", required_argument, 0, 'b'}, {"command", required_argument, 0, 'c'}, {"args", required_argument, 0, 'a'}, {"no-ssl", no_argument, 0, 'n'}, {"unknown-timeout", no_argument, 0, 'u'}, {"ipv4", no_argument, 0, '4'}, {"ipv6", no_argument, 0, '6'}, {"timeout", required_argument, 0, 't'}, {"port", required_argument, 0, 'p'}, {"help", no_argument, 0, 'h'}, {"license", no_argument, 0, 'l'}, {0, 0, 0, 0} }; #endif /* no options were supplied */ if(argc<2) return ERROR; snprintf(optchars,MAX_INPUT_BUFFER,"H:b:c:a:t:p:nu46hl"); while(1){ #ifdef HAVE_GETOPT_LONG c=getopt_long(argc,argv,optchars,long_options,&option_index); #else c=getopt(argc,argv,optchars); #endif if(c==-1 || c==EOF) break; /* process all arguments */ switch(c){ case '?': case 'h': show_help=TRUE; break; case 'b': bind_address=strdup(optarg); break; case 'V': show_version=TRUE; break; case 'l': show_license=TRUE; break; case 't': socket_timeout=atoi(optarg); if(socket_timeout<=0) return ERROR; break; case 'p': server_port=atoi(optarg); if(server_port<=0) return ERROR; break; case 'H': server_name=strdup(optarg); break; case 'c': command_name=strdup(optarg); break; case 'a': argindex=optind; break; case 'n': use_ssl=FALSE; break; case 'u': timeout_return_code=STATE_UNKNOWN; break; case '4': address_family=AF_INET; break; case '6': address_family=AF_INET6; break; default: return ERROR; break; } } /* determine (base) command query */ snprintf(query,sizeof(query),"%s",(command_name==NULL)?DEFAULT_NRPE_COMMAND:command_name); query[sizeof(query)-1]='\x0'; /* get the command args */ if(argindex>0){ for(c=argindex-1;c<argc;c++){ i=sizeof(query)-strlen(query)-2; if(i<=0) break; strcat(query,"!"); strncat(query,argv[c],i); query[sizeof(query)-1]='\x0'; } } /* make sure required args were supplied */ if(server_name==NULL && show_help==FALSE && show_version==FALSE && show_license==FALSE) return ERROR; return OK; } void alarm_handler(int sig){ printf("CHECK_NRPE: Socket timeout after %d seconds.\n",socket_timeout); exit(timeout_return_code); } /* submitted by Mark Plaksin 08/31/2006 */ int graceful_close(int sd, int timeout){ fd_set in; struct timeval tv; char buf[1000]; /* send FIN packet */ shutdown(sd,SHUT_WR); for(;;){ FD_ZERO(&in); FD_SET(sd,&in); tv.tv_sec=timeout/1000; tv.tv_usec=(timeout % 1000)*1000; /* timeout or error */ if(1!=select(sd+1,&in,NULL,NULL,&tv)) break; /* no more data (FIN or RST) */ if(0>=recv(sd,buf,sizeof(buf),0)) break; } #ifdef HAVE_CLOSESOCKET closesocket(sd); #else close(sd); #endif return OK; }