Back to index

nagios-nrpe  2.13
utils.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  *
00003  * UTILS.C - NRPE Utility Functions
00004  *
00005  * License: GPL
00006  * Copyright (c) 1999-2006 Ethan Galstad (nagios@nagios.org)
00007  *
00008  * Last Modified: 12-11-2006
00009  *
00010  * Description:
00011  *
00012  * This file contains common network functions used in nrpe and check_nrpe.
00013  *
00014  * License Information:
00015  *
00016  * This program is free software; you can redistribute it and/or modify
00017  * it under the terms of the GNU General Public License as published by
00018  * the Free Software Foundation; either version 2 of the License, or
00019  * (at your option) any later version.
00020  *
00021  * This program is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00029  *
00030  ****************************************************************************/
00031 
00032 #include "../include/common.h"
00033 #include "../include/utils.h"
00034 
00035 static unsigned long crc32_table[256];
00036 
00037 
00038 
00039 /* build the crc table - must be called before calculating the crc value */
00040 void generate_crc32_table(void){
00041        unsigned long crc, poly;
00042        int i, j;
00043 
00044        poly=0xEDB88320L;
00045        for(i=0;i<256;i++){
00046               crc=i;
00047               for(j=8;j>0;j--){
00048                      if(crc & 1)
00049                             crc=(crc>>1)^poly;
00050                      else
00051                             crc>>=1;
00052                       }
00053               crc32_table[i]=crc;
00054                 }
00055 
00056        return;
00057         }
00058 
00059 
00060 /* calculates the CRC 32 value for a buffer */
00061 unsigned long calculate_crc32(char *buffer, int buffer_size){
00062        register unsigned long crc;
00063        int this_char;
00064        int current_index;
00065 
00066        crc=0xFFFFFFFF;
00067 
00068        for(current_index=0;current_index<buffer_size;current_index++){
00069               this_char=(int)buffer[current_index];
00070               crc=((crc>>8) & 0x00FFFFFF) ^ crc32_table[(crc ^ this_char) & 0xFF];
00071                }
00072 
00073        return (crc ^ 0xFFFFFFFF);
00074         }
00075 
00076 
00077 /* fill a buffer with semi-random data */
00078 void randomize_buffer(char *buffer,int buffer_size){
00079        FILE *fp;
00080        int x;
00081        int seed;
00082 
00083        /**** FILL BUFFER WITH RANDOM ALPHA-NUMERIC CHARACTERS ****/
00084 
00085        /***************************************************************
00086           Only use alpha-numeric characters becase plugins usually
00087           only generate numbers and letters in their output.  We
00088           want the buffer to contain the same set of characters as
00089           plugins, so its harder to distinguish where the real output
00090           ends and the rest of the buffer (padded randomly) starts.
00091        ***************************************************************/
00092 
00093        /* try to get seed value from /dev/urandom, as its a better source of entropy */
00094        fp=fopen("/dev/urandom","r");
00095        if(fp!=NULL){
00096               seed=fgetc(fp);
00097               fclose(fp);
00098                }
00099 
00100        /* else fallback to using the current time as the seed */
00101        else
00102               seed=(int)time(NULL);
00103 
00104        srand(seed);
00105        for(x=0;x<buffer_size;x++)
00106               buffer[x]=(int)'0'+(int)(72.0*rand()/(RAND_MAX+1.0));
00107 
00108        return;
00109         }
00110 
00111 
00112 /* opens a connection to a remote host/tcp port */
00113 int my_tcp_connect(char *host_name,int port,int *sd){
00114        int result;
00115 
00116        result=my_connect(host_name,port,sd,"tcp");
00117 
00118        return result;
00119         }
00120 
00121 
00122 /* opens a tcp or udp connection to a remote host */
00123 int my_connect(char *host_name,int port,int *sd,char *proto){
00124        struct sockaddr_in servaddr;
00125        struct hostent *hp;
00126        struct protoent *ptrp;
00127        int result;
00128 
00129        bzero((char *)&servaddr,sizeof(servaddr));
00130        servaddr.sin_family=AF_INET;
00131        servaddr.sin_port=htons(port);
00132 
00133        /* try to bypass using a DNS lookup if this is just an IP address */
00134        if(!my_inet_aton(host_name,&servaddr.sin_addr)){
00135 
00136               /* else do a DNS lookup */
00137               hp=gethostbyname((const char *)host_name);
00138               if(hp==NULL){
00139                      printf("Invalid host name '%s'\n",host_name);
00140                      return STATE_UNKNOWN;
00141                       }
00142 
00143               memcpy(&servaddr.sin_addr,hp->h_addr,hp->h_length);
00144                }
00145 
00146        /* map transport protocol name to protocol number */
00147        if(((ptrp=getprotobyname(proto)))==NULL){
00148               printf("Cannot map \"%s\" to protocol number\n",proto);
00149               return STATE_UNKNOWN;
00150                }
00151 
00152        /* create a socket */
00153        *sd=socket(PF_INET,(!strcmp(proto,"udp"))?SOCK_DGRAM:SOCK_STREAM,ptrp->p_proto);
00154        if(*sd<0){
00155               printf("Socket creation failed\n");
00156               return STATE_UNKNOWN;
00157                }
00158 
00159        /* open a connection */
00160        result=connect(*sd,(struct sockaddr *)&servaddr,sizeof(servaddr));
00161        if(result<0){
00162               switch(errno){  
00163               case ECONNREFUSED:
00164                      printf("Connection refused by host\n");
00165                      break;
00166               case ETIMEDOUT:
00167                      printf("Timeout while attempting connection\n");
00168                      break;
00169               case ENETUNREACH:
00170                      printf("Network is unreachable\n");
00171                      break;
00172               default:
00173                      printf("Connection refused or timed out\n");
00174                       }
00175 
00176               return STATE_CRITICAL;
00177                }
00178 
00179        return STATE_OK;
00180         }
00181 
00182 
00183 
00184 /* This code was taken from Fyodor's nmap utility, which was originally taken from
00185    the GLIBC 2.0.6 libraries because Solaris doesn't contain the inet_aton() funtion. */
00186 int my_inet_aton(register const char *cp, struct in_addr *addr){
00187        register unsigned int val;  /* changed from u_long --david */
00188        register int base, n;
00189        register char c;
00190        u_int parts[4];
00191        register u_int *pp = parts;
00192 
00193        c=*cp;
00194 
00195        for(;;){
00196 
00197               /*
00198                * Collect number up to ``.''.
00199                * Values are specified as for C:
00200                * 0x=hex, 0=octal, isdigit=decimal.
00201                */
00202               if (!isdigit((int)c))
00203                      return (0);
00204               val=0;
00205               base=10;
00206 
00207               if(c=='0'){
00208                      c=*++cp;
00209                      if(c=='x'||c=='X')
00210                             base=16,c=*++cp;
00211                      else
00212                             base=8;
00213                       }
00214 
00215               for(;;){
00216                      if(isascii((int)c) && isdigit((int)c)){
00217                             val=(val*base)+(c -'0');
00218                             c=*++cp;
00219                              } 
00220                      else if(base==16 && isascii((int)c) && isxdigit((int)c)){
00221                             val=(val<<4) | (c+10-(islower((int)c)?'a':'A'));
00222                             c = *++cp;
00223                              } 
00224                      else
00225                             break;
00226                       }
00227 
00228               if(c=='.'){
00229 
00230                      /*
00231                       * Internet format:
00232                       *     a.b.c.d
00233                       *     a.b.c  (with c treated as 16 bits)
00234                       *     a.b    (with b treated as 24 bits)
00235                       */
00236                      if(pp>=parts+3)
00237                             return (0);
00238                      *pp++=val;
00239                      c=*++cp;
00240                       } 
00241               else
00242                      break;
00243                }
00244 
00245        /* Check for trailing characters */
00246        if(c!='\0' && (!isascii((int)c) || !isspace((int)c)))
00247               return (0);
00248 
00249        /* Concoct the address according to the number of parts specified */
00250        n=pp-parts+1;
00251        switch(n){
00252 
00253        case 0:
00254               return (0);          /* initial nondigit */
00255 
00256        case 1:                            /* a -- 32 bits */
00257               break;
00258 
00259        case 2:                            /* a.b -- 8.24 bits */
00260               if(val>0xffffff)
00261                      return (0);
00262               val|=parts[0]<<24;
00263               break;
00264 
00265        case 3:                            /* a.b.c -- 8.8.16 bits */
00266               if(val>0xffff)
00267                      return (0);
00268               val|=(parts[0]<< 24) | (parts[1]<<16);
00269               break;
00270 
00271        case 4:                            /* a.b.c.d -- 8.8.8.8 bits */
00272               if(val>0xff)
00273                      return (0);
00274               val|=(parts[0]<<24) | (parts[1]<<16) | (parts[2]<<8);
00275               break;
00276                }
00277 
00278        if(addr)
00279               addr->s_addr=htonl(val);
00280 
00281        return (1);
00282         }
00283 
00284 
00285 void strip(char *buffer){
00286        int x;
00287        int index;
00288 
00289        for(x=strlen(buffer);x>=1;x--){
00290               index=x-1;
00291               if(buffer[index]==' ' || buffer[index]=='\r' || buffer[index]=='\n' || buffer[index]=='\t')
00292                      buffer[index]='\x0';
00293               else
00294                      break;
00295                }
00296 
00297        return;
00298         }
00299 
00300 
00301 /* sends all data - thanks to Beej's Guide to Network Programming */
00302 int sendall(int s, char *buf, int *len){
00303        int total=0;
00304        int bytesleft=*len;
00305        int n=0;
00306 
00307        /* send all the data */
00308        while(total<*len){
00309 
00310               /* send some data */
00311               n=send(s,buf+total,bytesleft,0);
00312 
00313               /* break on error */
00314               if(n==-1)
00315                      break;
00316 
00317               /* apply bytes we sent */
00318               total+=n;
00319               bytesleft-=n;
00320                }
00321 
00322        /* return number of bytes actually send here */
00323        *len=total;
00324 
00325        /* return -1 on failure, 0 on success */
00326        return n==-1?-1:0;
00327         }
00328 
00329 
00330 /* receives all data - modelled after sendall() */
00331 int recvall(int s, char *buf, int *len, int timeout){
00332        int total=0;
00333        int bytesleft=*len;
00334        int n=0;
00335        time_t start_time;
00336        time_t current_time;
00337        
00338        /* clear the receive buffer */
00339        bzero(buf,*len);
00340 
00341        time(&start_time);
00342 
00343        /* receive all data */
00344        while(total<*len){
00345 
00346               /* receive some data */
00347               n=recv(s,buf+total,bytesleft,0);
00348 
00349               /* no data has arrived yet (non-blocking socket) */
00350               if(n==-1 && errno==EAGAIN){
00351                      time(&current_time);
00352                      if(current_time-start_time>timeout)
00353                             break;
00354                      sleep(1);
00355                      continue;
00356                       }
00357 
00358               /* receive error or client disconnect */
00359               else if(n<=0)
00360                      break;
00361 
00362               /* apply bytes we received */
00363               total+=n;
00364               bytesleft-=n;
00365                }
00366 
00367        /* return number of bytes actually received here */
00368        *len=total;
00369 
00370        /* return <=0 on failure, bytes received on success */
00371        return (n<=0)?n:total;
00372         }
00373 
00374 
00375 /* fixes compiler problems under Solaris, since strsep() isn't included */
00376 /* this code is taken from the glibc source */
00377 char *my_strsep (char **stringp, const char *delim){
00378        char *begin, *end;
00379 
00380        begin = *stringp;
00381        if (begin == NULL)
00382               return NULL;
00383 
00384        /* A frequent case is when the delimiter string contains only one
00385           character.  Here we don't need to call the expensive `strpbrk'
00386           function and instead work using `strchr'.  */
00387        if(delim[0]=='\0' || delim[1]=='\0'){
00388               char ch = delim[0];
00389 
00390               if(ch=='\0')
00391                      end=NULL;
00392               else{
00393                      if(*begin==ch)
00394                             end=begin;
00395                      else
00396                             end=strchr(begin+1,ch);
00397                      }
00398               }
00399 
00400        else
00401               /* Find the end of the token.  */
00402               end = strpbrk (begin, delim);
00403 
00404        if(end){
00405 
00406               /* Terminate the token and set *STRINGP past NUL character.  */
00407               *end++='\0';
00408               *stringp=end;
00409               }
00410        else
00411               /* No more delimiters; this is the last token.  */
00412               *stringp=NULL;
00413 
00414        return begin;
00415        }
00416 
00417 
00418 /* show license */
00419 void display_license(void){
00420 
00421        printf("This program is released under the GPL (see below) with the additional\n");
00422        printf("exemption that compiling, linking, and/or using OpenSSL is allowed.\n\n");
00423 
00424        printf("This program is free software; you can redistribute it and/or modify\n");
00425        printf("it under the terms of the GNU General Public License as published by\n");
00426        printf("the Free Software Foundation; either version 2 of the License, or\n");
00427        printf("(at your option) any later version.\n\n");
00428        printf("This program is distributed in the hope that it will be useful,\n");
00429        printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
00430        printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
00431        printf("GNU General Public License for more details.\n\n");
00432        printf("You should have received a copy of the GNU General Public License\n");
00433        printf("along with this program; if not, write to the Free Software\n");
00434        printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
00435 
00436        return;
00437         }
00438 
00439 
00440