/* Nosuid TCP/IP ping 1.5 beta by Michal Zalewski --------------------------------------------------------------- The Nosuid TCP/IP ping and related utilities are free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. changes by patrick haller http://www.haller.ws: ping now only uses ports 80, 22, 23, cycling through them. this fixes pings to sites that filter like cnn.com or netscape.com hacked by Doug Warner http://silfreed.net/ to be used w/ nagios/netsaint */ #include #include #include #include #include #include #include #include #include #include #include #ifndef SOLARIS #include #endif #ifdef SOLARIS #include #endif #define STATE_OK 0 #define STATE_WARNING 1 #define STATE_CRITICAL 2 #define STATE_UNKNOWN -1 char progname[] = "check_tcping"; char version[] = "0.1.5"; struct hostent *hp; struct sockaddr_in s; int suck,nic,to,tamto,count=5,delay=1,timeout=5,n=1,got,min,max,trip,port,warning_opt=0,critical_opt=0; struct timeval tv,tv2; char ad[20],ch; struct sigaction siga; int port_count = 0; int ports[] = { 80, 22, 161, 23 }; int found_port = 0; float wrta = 0.0; float wpl = 0.0; float crta = 0.0; float cpl = 0.0; void xerr(char* when) { perror(when); exit(errno); } void usage(void) { printf("usage:\n"); printf(" %s [ -i delay] [ -n #packets] [ -t timeout] [ -p port]\n", progname); printf(" -w ,<%%loss> -c ,<%%loss> host\n"); exit(STATE_UNKNOWN); } void alrm(int x) { int old_port = 0; old_port = port; to=1; if(! found_port){ port_count++; port = ports[port_count%4]; fprintf(stderr, "port %d not responding within timeout %d, changing to port %d
\n", old_port, timeout, port); } } void stats(int x) { /* printf("\n-- %s ping statistics --\n",ad); printf("%d packet(s) transmitted, %d packet(s) received, %d%% packets lost.\n",n-1,got,(n-1-got)*100/(n-1)); printf("round-trip statistics min/avg/max: "); if (got) { printf("%.2f/%.2f/%.2f ms",(float)min/1000,(float)trip/got/1000,(float)max/1000); if (min/1000<=0.1) printf(" (%d/%d/%d usecs)",min,trip/got,max); printf(".\n"); } else { printf("(not available due to 100%% packets lost).\n"); } exit(0); */ float currta = (float)trip/got/1000; float curpl = (n-1-got)*100/(n-1); int curstate = STATE_UNKNOWN; // determine current state if (currta < wrta && curpl < wpl && currta < crta && curpl < cpl) { curstate = STATE_OK; } else if ((currta >= wrta || curpl >= wpl) && (currta < crta && curpl < cpl)) { curstate = STATE_WARNING; } else if (currta >= crta || curpl >= cpl) { curstate = STATE_CRITICAL; } // end if state ok, warning, or critical // output current state printf("TCPING "); if (curstate == STATE_OK) { printf("OK"); } else if (curstate == STATE_WARNING) { printf("WARNING"); } else if (curstate == STATE_CRITICAL) { printf("CRITICAL"); } else { printf("UNKNOWN"); } // end if print stuff printf(": Packet loss = %.2f%%, RTA = ", curpl); if (got) { printf("%.2f ms", currta); } else { printf("(not available due to 100%% packets lost)"); } printf("\n"); // exit w/ current state exit(curstate); } int main (int argc, char **argv) { port = ports[port_count]; //printf("Nosuid TCP/IP ping 1.5 beta by \n"); while ((ch = getopt(argc, argv, "i:t:n:p:w:c:")) != EOF) { switch(ch) { case 'n': count=atoi(optarg); if (count<0) { fprintf(stderr,"%s: invalid number of pings.\n", progname);exit(STATE_UNKNOWN); } break; case 'i': delay=atoi(optarg); if (delay<1 || delay>1000) { fprintf(stderr,"%s: invalid ping delay.\n", progname);exit(STATE_UNKNOWN); } break; case 't': timeout=atoi(optarg); if (timeout<1 || timeout>100) { fprintf(stderr,"%s: invalid ping timeout.\n", progname);exit(STATE_UNKNOWN); } break; case 'p': port = atoi(optarg); break; case 'w': if (sscanf(optarg, "%f,%f", &wrta, &wpl) != 2) { fprintf(stderr, "%s: invalid number of options for warning\n", progname); exit(STATE_UNKNOWN); } warning_opt = 1; break; case 'c': if (sscanf(optarg, "%f,%f", &crta, &cpl) != 2) { fprintf(stderr, "%s: invalid number of options for critical\n", progname); exit(STATE_UNKNOWN); } critical_opt = 1; break; default: usage(); } } // end while still opts if (argc-optind!=1) usage(); min=timeout*1000000; hp=gethostbyname(argv[optind]); if (!hp) { printf("%s: host not found.\n", argv[0]); exit(STATE_UNKNOWN); } // test whether the warning or critical options were set if (warning_opt == 0) { printf("Warning option required\n"); exit(STATE_UNKNOWN); } // end if no warning option if (critical_opt == 0) { printf("Critical option required\n"); exit(STATE_UNKNOWN); } // end if no warning option nic=*(long*)hp->h_addr; sprintf(ad,"%d.%d.%d.%d",nic & 0xff,nic>>8 & 0xff,nic>>16 & 0xff, nic>>24 & 0xff); signal(SIGINT,stats); /* not needed for nagios - dw if (count) printf("Pinging %s (%s) - %d packets, delay %d sec(s), timeout %d sec(s).\n",hp->h_name,ad,count,delay,timeout); else printf("Pinging %s (%s) - delay %d sec(s), timeout %d sec(s).\n",hp->h_name,ad,delay,timeout); */ while (n++<=count || !count) { bcopy(hp->h_addr,(void*)&s.sin_addr,hp->h_length); s.sin_family=hp->h_addrtype; s.sin_port=htons(port); if ((suck=socket(AF_INET,SOCK_STREAM,0))<0) xerr("ping"); siga.sa_handler=alrm; errno=to=tamto=siga.sa_flags=0; sigaction(SIGALRM,&siga,NULL); alarm(timeout); gettimeofday(&tv,NULL); if (!connect(suck,(struct sockaddr *)&s,sizeof(s))) { if (to || errno==EINTR) { printf("No ping reply from %s within %d second(s), changing port to %d...\n", ad,timeout, port); } else if (errno && errno!=ECONNREFUSED) { xerr("ping"); } } gettimeofday(&tv2,NULL); alarm(timeout); if (!to ) { found_port=1; nic=(tv2.tv_sec-tv.tv_sec)*1000000+tv2.tv_usec-tv.tv_usec; /* not needed by nagios - dw if (nic/1000>=0.1) printf("Ping reply from %s: seq=%d, time=%.2f ms\n",ad,n-1,(float)nic/1000); else printf("Ping reply from %s: seq=%d, time=%d usecs\n",ad,n-1,nic); */ got++; trip+=nic; if (nic>max) max=nic; if (nic