#ifndef lint static char sccsid[] = "@(#)spray.c 1.1 88/03/07 4.0NFSSRC Copyr 1988 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include #include #define DEFBYTES 100000 /* default numbers of bytes to send */ #define MAXPACKETLEN 1514 char *adrtostr(int); void slp(int); void usage(void); void doicmp(int, int); char *host; int adr; int lnth, cnt; int icmp; int main(argc, argv) int argc; char **argv; { int err, i, rcved; int delay = 0; int psec, bsec; int buf[SPRAYMAX/4]; struct hostent *hp; struct sprayarr arr; struct spraycumul cumul; if (argc < 2) usage(); cnt = -1; lnth = SPRAYOVERHEAD; while (argc > 1) { if (argv[1][0] == '-') { switch(argv[1][1]) { case 'd': delay = atoi(argv[2]); argc--; argv++; break; case 'i': icmp++; break; case 'c': cnt = atoi(argv[2]); argc--; argv++; break; case 'l': lnth = atoi(argv[2]); argc--; argv++; break; default: usage(); } } else { if (host) usage(); else host = argv[1]; } argc--; argv++; } if (host == NULL) usage(); if (isinetaddr(host)) { adr = inet_addr(host); host = adrtostr(adr); } else { if ((hp = gethostbyname(host)) == NULL) { fprintf(stderr, "%s is unknown host name\n", host); exit(1); } adr = *((int *)hp->h_addr); } if (icmp) doicmp(adr, delay); if (cnt == -1) cnt = DEFBYTES/lnth; if (lnth < SPRAYOVERHEAD) lnth = SPRAYOVERHEAD; else if (lnth >= SPRAYMAX) lnth = SPRAYMAX; if (lnth <= MAXPACKETLEN && lnth % 4 != 2) lnth = ((lnth+5)/4)*4 - 2; arr.lnth = lnth - SPRAYOVERHEAD; arr.data = buf; printf("sending %d packets of lnth %d to %s ...", cnt, lnth, host); fflush(stdout); if (err = mycallrpc(adr, SPRAYPROG, SPRAYVERS, SPRAYPROC_CLEAR, xdr_void, NULL, xdr_void, NULL)) { fprintf(stderr, "SPRAYPROC_CLEAR "); clnt_perrno(err); fprintf(stderr, "\n"); return(err); } for (i = 0; i < cnt; i++) { callrpcnowait(adr, SPRAYPROG, SPRAYVERS, SPRAYPROC_SPRAY, xdr_sprayarr, &arr, xdr_void, NULL); if (delay > 0) slp(delay); } if (err = mycallrpc(adr, SPRAYPROG, SPRAYVERS, SPRAYPROC_GET, xdr_void, NULL, xdr_spraycumul, &cumul)) { fprintf(stderr, "SPRAYPROC_GET "); fprintf(stderr, "%s ", host); clnt_perrno(err); fprintf(stderr, "\n"); return(err); } if (cumul.counter < cnt) printf("\n\t%d packets (%.3f%%) dropped by %s\n", cnt - cumul.counter, 100.0*(cnt - cumul.counter)/cnt, host); else printf("\n\tno packets dropped by %s\n", host); psec = (1000000.0 * cumul.counter) / (1000000.0 * cumul.clock.tv_sec + cumul.clock.tv_usec); bsec = (lnth * 1000000.0 * cumul.counter)/ (1000000.0 * cumul.clock.tv_sec + cumul.clock.tv_usec); printf("\t%d packets/sec, %d bytes/sec\n", psec, bsec); return(0); } /* * like callrpc, but with addr instead of host name */ mycallrpc(addr, prognum, versnum, procnum, inproc, in, outproc, out) xdrproc_t inproc, outproc; char *in, *out; { struct sockaddr_in server_addr; enum clnt_stat clnt_stat; struct timeval timeout, tottimeout; static CLIENT *client; static int socket = RPC_ANYSOCK; static int oldprognum, oldversnum, valid; static int oldadr; if (valid && oldprognum == prognum && oldversnum == versnum && adr == oldadr) { /* reuse old client */ } else { close(socket); socket = RPC_ANYSOCK; if (client) { clnt_destroy(client); client = NULL; } timeout.tv_usec = 0; timeout.tv_sec = 10; bcopy(&adr, &server_addr.sin_addr, sizeof(adr)); server_addr.sin_family = AF_INET; server_addr.sin_port = 0; if ((client = clntudp_create(&server_addr, prognum, versnum, timeout, &socket)) == NULL) return ((int) rpc_createerr.cf_stat); valid = 1; oldprognum = prognum; oldversnum = versnum; oldadr = adr; } tottimeout.tv_sec = 25; tottimeout.tv_usec = 0; clnt_stat = clnt_call(client, procnum, inproc, in, outproc, out, tottimeout); /* * if call failed, empty cache */ if (clnt_stat != RPC_SUCCESS) valid = 0; return ((int) clnt_stat); } callrpcnowait(adr, prognum, versnum, procnum, inproc, in, outproc, out) xdrproc_t inproc, outproc; char *in, *out; { struct sockaddr_in server_addr; enum clnt_stat clnt_stat; struct timeval timeout, tottimeout; static CLIENT *client; static int socket = RPC_ANYSOCK; static int oldprognum, oldversnum, valid; static int oldadr; if (valid && oldprognum == prognum && oldversnum == versnum && oldadr == adr) { /* reuse old client */ } else { close(socket); socket = RPC_ANYSOCK; if (client) { clnt_destroy(client); client = NULL; } timeout.tv_usec = 0; timeout.tv_sec = 0; bcopy(&adr, &server_addr.sin_addr, sizeof(adr)); server_addr.sin_family = AF_INET; server_addr.sin_port = 0; if ((client = clntudp_create(&server_addr, prognum, versnum, timeout, &socket)) == NULL) return ((int) rpc_createerr.cf_stat); valid = 1; oldprognum = prognum; oldversnum = versnum; oldadr = adr; } tottimeout.tv_sec = 0; tottimeout.tv_usec = 0; clnt_stat = clnt_call(client, procnum, inproc, in, outproc, out, tottimeout); /* * if call failed, empty cache * since timeout is zero, normal return value is RPC_TIMEDOUT */ if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) valid = 0; return ((int) clnt_stat); } char * adrtostr(adr) int adr; { struct hostent *hp; static char buf[sizeof "0xnnnnnnnn"]; hp = gethostbyaddr((char *)&adr, sizeof(adr), AF_INET); if (hp == NULL) { sprintf(buf, "0x%x", adr); return buf; } return hp->h_name; } void slp(usecs) int usecs; { struct timeval tv; tv.tv_sec = usecs / 1000000; tv.tv_usec = usecs % 1000000; select(32, 0, 0, 0, &tv); } #include #include #include #include #define MAXICMP (2082 - IPHEADER) /* experimentally determined to be max */ #define IPHEADER 34 /* size of ether + ip header */ #define MINICMP 8 /* minimum icmp length */ struct timeval tv1, tv2; int pid, rcvd; void die(int), done(int); void doicmp(adr, delay) int adr, delay; { char buf[MAXICMP]; struct icmp *icp = (struct icmp *)buf; int i, s; int fromlen, size; struct sockaddr_in to, from; cap_t ocap; cap_value_t cap_priv_port = CAP_PRIV_PORT; ocap = cap_acquire(1, &cap_priv_port); if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { cap_surrender(ocap); perror("ping: socket"); exit(1); } cap_surrender(ocap); if (lnth >= IPHEADER + MINICMP) lnth -= IPHEADER; else lnth = MINICMP; if (lnth > MAXICMP) { fprintf(stderr, "%d is max packet size\n", MAXICMP + IPHEADER); exit(1); } if (cnt == -1) cnt = DEFBYTES/(lnth+IPHEADER); to.sin_family = AF_INET; to.sin_port = 0; to.sin_addr.s_addr = adr; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_id = 1; icp->icmp_seq = 1; icp->icmp_cksum = in_cksum(icp, lnth); printf("sending %d packets of lnth %d to %s ...", cnt, lnth+IPHEADER, host); fflush(stdout); if ((pid = fork()) < 0) { perror("ping: fork"); exit(1); } if (pid == 0) { /* child */ sleep(1); /* wait a second to give parent time to recv */ for (i = 0; i < cnt; i++) { if (sendto(s, icp, lnth, 0, &to, sizeof(to)) != lnth) { perror("ping: sendto"); if (errno != ENOBUFS) exit(1); } if (delay > 0) slp(delay); } sleep(1); /* wait for last echo to get thru */ exit(0); } if (pid != 0) { /* parent */ signal(SIGCHLD, done); signal(SIGINT, die); rcvd = 0; for (i = 0; ; i++) { fromlen = sizeof(from); if ((size = recvfrom(s, buf, sizeof(buf), 0, &from, &fromlen)) < 0) { perror("ping: recvfrom"); continue; } if (i == 0) gettimeofday(&tv1, 0); else if (i == cnt-1) gettimeofday(&tv2, 0); rcvd++; } } } in_cksum(addr, len) u_short *addr; int len; { register u_short *ptr; register int sum; u_short *lastptr; sum = 0; ptr = (u_short *)addr; lastptr = ptr + (len/2); for (; ptr < lastptr; ptr++) { sum += *ptr; if (sum & 0x10000) { sum &= 0xffff; sum++; } } return (~sum & 0xffff); } void die(int sig) { kill (pid, SIGKILL); exit(1); } void done(int sig) { int psec, bsec; if (tv2.tv_usec == 0 && tv2.tv_usec == 0) {/* estimate */ gettimeofday(&tv2, 0); tv2.tv_sec -= 1; /* allow for sleep(1) */ } if (rcvd != cnt) printf("\n\t%d packets (%.3f%%) dropped by %s\n", cnt - rcvd, 100.0*(cnt - rcvd)/cnt, host); else printf("\n\tno packets dropped by %s\n", host); if (tv2.tv_usec < tv1.tv_usec) { tv2.tv_usec += 1000000; tv2.tv_sec -= 1; } tv2.tv_sec -= tv1.tv_sec; tv2.tv_usec -= tv1.tv_usec; psec = (1000000.0*cnt) / (1000000.0*tv2.tv_sec + tv2.tv_usec); bsec = ((lnth + IPHEADER) * 1000000.0 * cnt)/ (1000000.0 * tv2.tv_sec + tv2.tv_usec); printf("\t%d packets/sec, %d bytes/sec\n", psec, bsec); exit(0); } void usage(void) { fprintf(stderr, "Usage: spray host [-i] [-c cnt] [-l lnth] [-d usecs]\n"); exit(1); } /* * A better way to check for an inet address : scan the entire string for * nothing but . and digits. If a letter is found return FALSE. Yes, you can * get some degenerate cases by it, but who names a host with *all* numbers? */ int isinetaddr(str) char *str; { int i; while (*str) if (((*str >= '0') && (*str <= '9')) || (*str == '.')) str++; else return(FALSE); return(TRUE); }