bsdping.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. /* BSDI ping.c,v 2.3 1996/01/21 17:56:50 jch Exp */
  2. /*
  3. * Copyright (c) 1989, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Mike Muuss.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. All advertising materials mentioning features or use of this software
  18. * must display the following acknowledgement:
  19. * This product includes software developed by the University of
  20. * California, Berkeley and its contributors.
  21. * 4. Neither the name of the University nor the names of its contributors
  22. * may be used to endorse or promote products derived from this software
  23. * without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35. * SUCH DAMAGE.
  36. */
  37. #ifndef lint
  38. static char copyright[] =
  39. "@(#) Copyright (c) 1989, 1993\n\
  40. The Regents of the University of California. All rights reserved.\n";
  41. #endif /* not lint */
  42. #ifndef lint
  43. static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
  44. #endif /* not lint */
  45. /*
  46. * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  47. * measure round-trip-delays and packet loss across network paths.
  48. *
  49. * Author -
  50. * Mike Muuss
  51. * U. S. Army Ballistic Research Laboratory
  52. * December, 1983
  53. *
  54. * Status -
  55. * Public Domain. Distribution Unlimited.
  56. * Bugs -
  57. * More statistics could always be gathered.
  58. * This program has to run SUID to ROOT to access the ICMP socket.
  59. */
  60. #include <sys/param.h>
  61. #include <sys/socket.h>
  62. #include <sys/time.h>
  63. #include <netinet/in_systm.h>
  64. #include <netinet/in.h>
  65. #include <netinet/ip.h>
  66. #include <netinet/ip_icmp.h>
  67. #include <netinet/ip_var.h>
  68. #include <arpa/inet.h>
  69. #include <netdb.h>
  70. #include <ctype.h>
  71. #include <err.h>
  72. #include <errno.h>
  73. #include <fcntl.h>
  74. #include <signal.h>
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <unistd.h>
  79. #define DEFDATALEN (64 - 8) /* default data length */
  80. #define MAXIPLEN 60
  81. #define MAXICMPLEN 76
  82. #define MAXPACKET (65536 - 60 - 8)/* max packet size */
  83. #define NROUTES 9 /* number of record route slots */
  84. #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
  85. #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
  86. #define SET(bit) (A(bit) |= B(bit))
  87. #define CLR(bit) (A(bit) &= (~B(bit)))
  88. #define TST(bit) (A(bit) & B(bit))
  89. #define F_FLOOD 0x0001
  90. #define F_INTERVAL 0x0002
  91. #define F_NUMERIC 0x0004
  92. #define F_PINGFILLED 0x0008
  93. #define F_QUIET 0x0010
  94. #define F_RROUTE 0x0020
  95. #define F_SO_DEBUG 0x0040
  96. #define F_SO_DONTROUTE 0x0080
  97. #define F_VERBOSE 0x0100
  98. u_int options;
  99. /*
  100. * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
  101. * number of received sequence numbers we can keep track of. Change 128
  102. * to 8192 for complete accuracy...
  103. */
  104. #define MAX_DUP_CHK (8 * 8192)
  105. int mx_dup_ck = MAX_DUP_CHK;
  106. char rcvd_tbl[MAX_DUP_CHK / 8];
  107. struct sockaddr whereto; /* who to ping */
  108. int datalen = DEFDATALEN;
  109. int s; /* socket file descriptor */
  110. u_char outpack[MAXPACKET];
  111. char BSPACE = '\b'; /* characters written for flood */
  112. char DOT = '.';
  113. char *hostname;
  114. int ident; /* process id to identify our packets */
  115. /* counters */
  116. long npackets; /* max packets to transmit */
  117. long nreceived; /* # of packets we got back */
  118. long nrepeats; /* number of duplicates */
  119. long ntransmitted; /* sequence # for outbound packets = #sent */
  120. int interval = 1; /* interval between packets */
  121. /* timing */
  122. int timing; /* flag to do timing */
  123. double tmin = 999999999.0; /* minimum round trip time */
  124. double tmax = 0.0; /* maximum round trip time */
  125. double tsum = 0.0; /* sum of all times, for doing average */
  126. void fill __P((char *, char *));
  127. u_short in_cksum __P((u_short *, int));
  128. void onalrm __P((int));
  129. void oninfo __P((int));
  130. void onint __P((int));
  131. void pinger __P((void));
  132. char *pr_addr __P((u_long));
  133. void pr_icmph __P((struct icmp *));
  134. void pr_iph __P((struct ip *));
  135. void pr_pack __P((char *, int, struct sockaddr_in *));
  136. void pr_retip __P((struct ip *));
  137. void summary __P((void));
  138. void tvsub __P((struct timeval *, struct timeval *));
  139. void usage __P((void));
  140. int
  141. main(argc, argv)
  142. int argc;
  143. char *argv[];
  144. {
  145. extern int errno, optind;
  146. extern char *optarg;
  147. struct hostent *hp;
  148. struct itimerval itimer;
  149. struct protoent *proto;
  150. struct sockaddr_in *to, from;
  151. struct timeval timeout;
  152. fd_set fdset;
  153. register int cc, i;
  154. int ch, fromlen, hold, packlen, preload;
  155. u_char *datap, *packet;
  156. char *e, *target, hnamebuf[MAXHOSTNAMELEN];
  157. #ifdef IP_OPTIONS
  158. char rspace[3 + 4 * NROUTES + 1]; /* record route space */
  159. #endif
  160. preload = 0;
  161. datap = &outpack[8 + sizeof(struct timeval)];
  162. while ((ch = getopt(argc, argv, "c:dfi:l:np:qRrs:v")) != -1)
  163. switch(ch) {
  164. case 'c':
  165. npackets = strtol(optarg, &e, 10);
  166. if (npackets <= 0 || *optarg == '\0' || *e != '\0')
  167. errx(1,
  168. "illegal number of packets -- %s", optarg);
  169. break;
  170. case 'd':
  171. options |= F_SO_DEBUG;
  172. break;
  173. case 'f':
  174. if (getuid()) {
  175. errno = EPERM;
  176. err(1, NULL);
  177. }
  178. options |= F_FLOOD;
  179. setbuf(stdout, (char *)NULL);
  180. break;
  181. case 'i': /* wait between sending packets */
  182. interval = strtol(optarg, &e, 10);
  183. if (interval <= 0 || *optarg == '\0' || *e != '\0')
  184. errx(1,
  185. "illegal timing interval -- %s", optarg);
  186. options |= F_INTERVAL;
  187. break;
  188. case 'l':
  189. preload = strtol(optarg, &e, 10);
  190. if (preload < 0 || *optarg == '\0' || *e != '\0')
  191. errx(1, "illegal preload value -- %s", optarg);
  192. break;
  193. case 'n':
  194. options |= F_NUMERIC;
  195. break;
  196. case 'p': /* fill buffer with user pattern */
  197. options |= F_PINGFILLED;
  198. fill((char *)datap, optarg);
  199. break;
  200. case 'q':
  201. options |= F_QUIET;
  202. break;
  203. case 'R':
  204. options |= F_RROUTE;
  205. break;
  206. case 'r':
  207. options |= F_SO_DONTROUTE;
  208. break;
  209. case 's': /* size of packet to send */
  210. datalen = strtol(optarg, &e, 10);
  211. if (datalen <= 0 || *optarg == '\0' || *e != '\0')
  212. errx(1, "illegal datalen value -- %s", optarg);
  213. if (datalen > MAXPACKET)
  214. errx(1,
  215. "datalen value too large, maximum is %d",
  216. MAXPACKET);
  217. break;
  218. case 'v':
  219. options |= F_VERBOSE;
  220. break;
  221. default:
  222. usage();
  223. }
  224. argc -= optind;
  225. argv += optind;
  226. if (argc != 1)
  227. usage();
  228. target = *argv;
  229. memset(&whereto, 0, sizeof(struct sockaddr));
  230. to = (struct sockaddr_in *)&whereto;
  231. to->sin_family = AF_INET;
  232. to->sin_addr.s_addr = inet_addr(target);
  233. if (to->sin_addr.s_addr != (u_int)-1)
  234. hostname = target;
  235. else {
  236. hp = gethostbyname(target);
  237. if (!hp)
  238. errx(1, "unknown host %s", target);
  239. to->sin_family = hp->h_addrtype;
  240. memmove(&to->sin_addr, hp->h_addr, hp->h_length);
  241. (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
  242. hostname = hnamebuf;
  243. }
  244. if (options & F_FLOOD && options & F_INTERVAL)
  245. errx(1, "-f and -i incompatible options");
  246. if (datalen >= sizeof(struct timeval)) /* can we time transfer */
  247. timing = 1;
  248. packlen = datalen + MAXIPLEN + MAXICMPLEN;
  249. if (!(packet = (u_char *)malloc((u_int)packlen)))
  250. err(1, NULL);
  251. if (!(options & F_PINGFILLED))
  252. for (i = 8; i < datalen; ++i)
  253. *datap++ = i;
  254. ident = getpid() & 0xFFFF;
  255. if (!(proto = getprotobyname("icmp")))
  256. errx(1, "unknown protocol icmp");
  257. if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0)
  258. err(1, "socket");
  259. hold = 1;
  260. if (options & F_SO_DEBUG)
  261. (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  262. sizeof(hold));
  263. if (options & F_SO_DONTROUTE)
  264. (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
  265. sizeof(hold));
  266. /* record route option */
  267. if (options & F_RROUTE) {
  268. #ifdef IP_OPTIONS
  269. rspace[IPOPT_OPTVAL] = IPOPT_RR;
  270. rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  271. rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  272. if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  273. sizeof(rspace)) < 0)
  274. err(1, "record route");
  275. #else
  276. errx(1, "record route not available in this implementation");
  277. #endif
  278. }
  279. /*
  280. * When pinging the broadcast address, you can get a lot of answers.
  281. * Doing something so evil is useful if you are trying to stress the
  282. * ethernet, or just want to fill the arp cache to get some stuff for
  283. * /etc/ethers.
  284. */
  285. hold = 48 * 1024;
  286. (void)setsockopt(s,
  287. SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
  288. if (to->sin_family == AF_INET)
  289. (void)printf("PING %s (%s): %d data bytes\n", hostname,
  290. inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
  291. datalen);
  292. else
  293. (void)printf("PING %s: %d data bytes\n", hostname, datalen);
  294. while (preload--) /* Fire off them quickies. */
  295. pinger();
  296. (void)signal(SIGINT, onint);
  297. (void)signal(SIGINFO, oninfo);
  298. if ((options & F_FLOOD) == 0) {
  299. (void)signal(SIGALRM, onalrm);
  300. itimer.it_interval.tv_sec = interval;
  301. itimer.it_interval.tv_usec = 0;
  302. itimer.it_value.tv_sec = 0;
  303. itimer.it_value.tv_usec = 1;
  304. (void)setitimer(ITIMER_REAL, &itimer, NULL);
  305. }
  306. FD_ZERO(&fdset);
  307. timeout.tv_sec = 0;
  308. timeout.tv_usec = 10000;
  309. for (;;) {
  310. if (options & F_FLOOD) {
  311. pinger();
  312. FD_SET(s, &fdset);
  313. if (select(s + 1, &fdset, NULL, NULL, &timeout) < 1)
  314. continue;
  315. }
  316. fromlen = sizeof(from);
  317. if ((cc = recvfrom(s, (char *)packet, packlen, 0,
  318. (struct sockaddr *)&from, &fromlen)) < 0) {
  319. if (errno == EINTR)
  320. continue;
  321. warn("recvfrom");
  322. continue;
  323. }
  324. pr_pack((char *)packet, cc, &from);
  325. if (npackets && nreceived >= npackets)
  326. break;
  327. }
  328. summary();
  329. exit(nreceived == 0);
  330. }
  331. /*
  332. * onalrm --
  333. * This routine transmits another ping.
  334. */
  335. void
  336. onalrm(signo)
  337. int signo;
  338. {
  339. struct itimerval itimer;
  340. if (!npackets || ntransmitted < npackets) {
  341. pinger();
  342. return;
  343. }
  344. /*
  345. * If we're not transmitting any more packets, change the timer
  346. * to wait two round-trip times if we've received any packets or
  347. * ten seconds if we haven't.
  348. */
  349. #define MAXWAIT 10
  350. if (nreceived) {
  351. itimer.it_value.tv_sec = 2 * tmax / 1000;
  352. if (itimer.it_value.tv_sec == 0)
  353. itimer.it_value.tv_sec = 1;
  354. } else
  355. itimer.it_value.tv_sec = MAXWAIT;
  356. itimer.it_interval.tv_sec = 0;
  357. itimer.it_interval.tv_usec = 0;
  358. itimer.it_value.tv_usec = 0;
  359. (void)signal(SIGALRM, onint);
  360. (void)setitimer(ITIMER_REAL, &itimer, NULL);
  361. }
  362. /*
  363. * pinger --
  364. * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
  365. * will be added on by the kernel. The ID field is our UNIX process ID,
  366. * and the sequence number is an ascending integer. The first 8 bytes
  367. * of the data portion are used to hold a UNIX "timeval" struct in VAX
  368. * byte-order, to compute the round-trip time.
  369. */
  370. void
  371. pinger()
  372. {
  373. register struct icmp *icp;
  374. register int cc;
  375. int i;
  376. icp = (struct icmp *)outpack;
  377. icp->icmp_type = ICMP_ECHO;
  378. icp->icmp_code = 0;
  379. icp->icmp_cksum = 0;
  380. icp->icmp_seq = ntransmitted++;
  381. icp->icmp_id = ident; /* ID */
  382. CLR(icp->icmp_seq % mx_dup_ck);
  383. if (timing)
  384. (void)gettimeofday((struct timeval *)&outpack[8], NULL);
  385. cc = datalen + 8; /* skips ICMP portion */
  386. /* compute ICMP checksum here */
  387. icp->icmp_cksum = in_cksum((u_short *)icp, cc);
  388. i = sendto(s, (char *)outpack, cc, 0, &whereto,
  389. sizeof(struct sockaddr));
  390. if (i < 0 || i != cc) {
  391. if (i < 0)
  392. warn("sendto");
  393. (void)printf("ping: wrote %s %d chars, ret=%d\n",
  394. hostname, cc, i);
  395. }
  396. if (!(options & F_QUIET) && options & F_FLOOD)
  397. (void)write(STDOUT_FILENO, &DOT, 1);
  398. }
  399. /*
  400. * pr_pack --
  401. * Print out the packet, if it came from us. This logic is necessary
  402. * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  403. * which arrive ('tis only fair). This permits multiple copies of this
  404. * program to be run without having intermingled output (or statistics!).
  405. */
  406. void
  407. pr_pack(buf, cc, from)
  408. char *buf;
  409. int cc;
  410. struct sockaddr_in *from;
  411. {
  412. register struct icmp *icp;
  413. register u_long l;
  414. register int i, j;
  415. register u_char *cp,*dp;
  416. static int old_rrlen;
  417. static char old_rr[MAX_IPOPTLEN];
  418. struct ip *ip;
  419. struct timeval tv, *tp;
  420. double triptime;
  421. int hlen, dupflag;
  422. (void)gettimeofday(&tv, NULL);
  423. /* Check the IP header */
  424. ip = (struct ip *)buf;
  425. hlen = ip->ip_hl << 2;
  426. if (cc < hlen + ICMP_MINLEN) {
  427. if (options & F_VERBOSE)
  428. warnx("packet too short (%d bytes) from %s\n", cc,
  429. inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  430. return;
  431. }
  432. /* Now the ICMP part */
  433. cc -= hlen;
  434. icp = (struct icmp *)(buf + hlen);
  435. if (icp->icmp_type == ICMP_ECHOREPLY) {
  436. if (icp->icmp_id != ident)
  437. return; /* 'Twas not our ECHO */
  438. ++nreceived;
  439. if (timing) {
  440. #ifndef icmp_data
  441. tp = (struct timeval *)&icp->icmp_ip;
  442. #else
  443. tp = (struct timeval *)icp->icmp_data;
  444. #endif
  445. tvsub(&tv, tp);
  446. triptime = ((double)tv.tv_sec) * 1000.0 +
  447. ((double)tv.tv_usec) / 1000.0;
  448. tsum += triptime;
  449. if (triptime < tmin)
  450. tmin = triptime;
  451. if (triptime > tmax)
  452. tmax = triptime;
  453. }
  454. if (TST(icp->icmp_seq % mx_dup_ck)) {
  455. ++nrepeats;
  456. --nreceived;
  457. dupflag = 1;
  458. } else {
  459. SET(icp->icmp_seq % mx_dup_ck);
  460. dupflag = 0;
  461. }
  462. if (options & F_QUIET)
  463. return;
  464. if (options & F_FLOOD)
  465. (void)write(STDOUT_FILENO, &BSPACE, 1);
  466. else {
  467. (void)printf("%d bytes from %s: icmp_seq=%u", cc,
  468. inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
  469. icp->icmp_seq);
  470. (void)printf(" ttl=%d", ip->ip_ttl);
  471. if (timing)
  472. (void)printf(" time=%g ms", triptime);
  473. if (dupflag)
  474. (void)printf(" (DUP!)");
  475. /* check the data */
  476. cp = (u_char*)&icp->icmp_data[8];
  477. dp = &outpack[8 + sizeof(struct timeval)];
  478. for (i = 8; i < datalen; ++i, ++cp, ++dp) {
  479. if (*cp != *dp) {
  480. (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  481. i, *dp, *cp);
  482. cp = (u_char*)&icp->icmp_data[0];
  483. for (i = 8; i < datalen; ++i, ++cp) {
  484. if ((i % 32) == 8)
  485. (void)printf("\n\t");
  486. (void)printf("%x ", *cp);
  487. }
  488. break;
  489. }
  490. }
  491. }
  492. } else {
  493. /* We've got something other than an ECHOREPLY */
  494. if (!(options & F_VERBOSE))
  495. return;
  496. (void)printf("%d bytes from %s: ", cc,
  497. pr_addr(from->sin_addr.s_addr));
  498. pr_icmph(icp);
  499. }
  500. /* Display any IP options */
  501. cp = (u_char *)buf + sizeof(struct ip);
  502. for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
  503. switch (*cp) {
  504. case IPOPT_EOL:
  505. hlen = 0;
  506. break;
  507. case IPOPT_LSRR:
  508. (void)printf("\nLSRR: ");
  509. hlen -= 2;
  510. j = *++cp;
  511. ++cp;
  512. if (j > IPOPT_MINOFF)
  513. for (;;) {
  514. l = *++cp;
  515. l = (l<<8) + *++cp;
  516. l = (l<<8) + *++cp;
  517. l = (l<<8) + *++cp;
  518. if (l == 0)
  519. (void)printf("\t0.0.0.0");
  520. else
  521. (void)printf("\t%s", pr_addr(ntohl(l)));
  522. hlen -= 4;
  523. j -= 4;
  524. if (j <= IPOPT_MINOFF)
  525. break;
  526. (void)putchar('\n');
  527. }
  528. break;
  529. case IPOPT_RR:
  530. j = *++cp; /* get length */
  531. i = *++cp; /* and pointer */
  532. hlen -= 2;
  533. if (i > j)
  534. i = j;
  535. i -= IPOPT_MINOFF;
  536. if (i <= 0)
  537. continue;
  538. if (i == old_rrlen
  539. && cp == (u_char *)buf + sizeof(struct ip) + 2
  540. && !memcmp((char *)cp, old_rr, i)
  541. && !(options & F_FLOOD)) {
  542. (void)printf("\t(same route)");
  543. i = ((i + 3) / 4) * 4;
  544. hlen -= i;
  545. cp += i;
  546. break;
  547. }
  548. old_rrlen = i;
  549. memmove(old_rr, cp, i);
  550. (void)printf("\nRR: ");
  551. for (;;) {
  552. l = *++cp;
  553. l = (l<<8) + *++cp;
  554. l = (l<<8) + *++cp;
  555. l = (l<<8) + *++cp;
  556. if (l == 0)
  557. (void)printf("\t0.0.0.0");
  558. else
  559. (void)printf("\t%s", pr_addr(ntohl(l)));
  560. hlen -= 4;
  561. i -= 4;
  562. if (i <= 0)
  563. break;
  564. (void)putchar('\n');
  565. }
  566. break;
  567. case IPOPT_NOP:
  568. (void)printf("\nNOP");
  569. break;
  570. default:
  571. (void)printf("\nunknown option %x", *cp);
  572. break;
  573. }
  574. if (!(options & F_FLOOD)) {
  575. (void)putchar('\n');
  576. (void)fflush(stdout);
  577. }
  578. }
  579. /*
  580. * in_cksum --
  581. * Checksum routine for Internet Protocol family headers (C Version)
  582. */
  583. u_short
  584. in_cksum(addr, len)
  585. u_short *addr;
  586. int len;
  587. {
  588. register int nleft = len;
  589. register u_short *w = addr;
  590. register int sum = 0;
  591. u_short answer = 0;
  592. /*
  593. * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  594. * sequential 16 bit words to it, and at the end, fold back all the
  595. * carry bits from the top 16 bits into the lower 16 bits.
  596. */
  597. while (nleft > 1) {
  598. sum += *w++;
  599. nleft -= 2;
  600. }
  601. /* mop up an odd byte, if necessary */
  602. if (nleft == 1) {
  603. *(u_char *)(&answer) = *(u_char *)w ;
  604. sum += answer;
  605. }
  606. /* add back carry outs from top 16 bits to low 16 bits */
  607. sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
  608. sum += (sum >> 16); /* add carry */
  609. answer = ~sum; /* truncate to 16 bits */
  610. return (answer);
  611. }
  612. /*
  613. * tvsub --
  614. * Subtract 2 timeval structs: out = out - in. Out is assumed to
  615. * be >= in.
  616. */
  617. void
  618. tvsub(out, in)
  619. register struct timeval *out, *in;
  620. {
  621. if ((out->tv_usec -= in->tv_usec) < 0) {
  622. --out->tv_sec;
  623. out->tv_usec += 1000000;
  624. }
  625. out->tv_sec -= in->tv_sec;
  626. }
  627. /*
  628. * oninfo --
  629. * SIGINFO handler.
  630. */
  631. void
  632. oninfo(notused)
  633. int notused;
  634. {
  635. summary();
  636. }
  637. /*
  638. * onint --
  639. * SIGINT handler.
  640. */
  641. void
  642. onint(notused)
  643. int notused;
  644. {
  645. summary();
  646. (void)signal(SIGINT, SIG_DFL);
  647. (void)kill(getpid(), SIGINT);
  648. /* NOTREACHED */
  649. exit(1);
  650. }
  651. /*
  652. * summary --
  653. * Print out statistics.
  654. */
  655. void
  656. summary()
  657. {
  658. register int i;
  659. (void)printf("\n--- %s ping statistics ---\n", hostname);
  660. (void)printf("%ld packets transmitted, ", ntransmitted);
  661. (void)printf("%ld packets received, ", nreceived);
  662. if (nrepeats)
  663. (void)printf("+%ld duplicates, ", nrepeats);
  664. if (ntransmitted)
  665. if (nreceived > ntransmitted)
  666. (void)printf("-- somebody's printing up packets!");
  667. else
  668. (void)printf("%d%% packet loss",
  669. (int) (((ntransmitted - nreceived) * 100) /
  670. ntransmitted));
  671. (void)putchar('\n');
  672. if (nreceived && timing) {
  673. /* Only display average to microseconds */
  674. i = 1000.0 * tsum / (nreceived + nrepeats);
  675. (void)printf("round-trip min/avg/max = %g/%g/%g ms\n",
  676. tmin, ((double)i) / 1000.0, tmax);
  677. }
  678. }
  679. #ifdef notdef
  680. static char *ttab[] = {
  681. "Echo Reply", /* ip + seq + udata */
  682. "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
  683. "Source Quench", /* IP */
  684. "Redirect", /* redirect type, gateway, + IP */
  685. "Echo",
  686. "Time Exceeded", /* transit, frag reassem + IP */
  687. "Parameter Problem", /* pointer + IP */
  688. "Timestamp", /* id + seq + three timestamps */
  689. "Timestamp Reply", /* " */
  690. "Info Request", /* id + sq */
  691. "Info Reply" /* " */
  692. };
  693. #endif
  694. /*
  695. * pr_icmph --
  696. * Print a descriptive string about an ICMP header.
  697. */
  698. void
  699. pr_icmph(icp)
  700. struct icmp *icp;
  701. {
  702. switch(icp->icmp_type) {
  703. case ICMP_ECHOREPLY:
  704. (void)printf("Echo Reply\n");
  705. /* XXX ID + Seq + Data */
  706. break;
  707. case ICMP_UNREACH:
  708. switch(icp->icmp_code) {
  709. case ICMP_UNREACH_NET:
  710. (void)printf("Destination Net Unreachable\n");
  711. break;
  712. case ICMP_UNREACH_HOST:
  713. (void)printf("Destination Host Unreachable\n");
  714. break;
  715. case ICMP_UNREACH_PROTOCOL:
  716. (void)printf("Destination Protocol Unreachable\n");
  717. break;
  718. case ICMP_UNREACH_PORT:
  719. (void)printf("Destination Port Unreachable\n");
  720. break;
  721. case ICMP_UNREACH_NEEDFRAG:
  722. (void)printf("frag needed and DF set\n");
  723. break;
  724. case ICMP_UNREACH_SRCFAIL:
  725. (void)printf("Source Route Failed\n");
  726. break;
  727. default:
  728. (void)printf("Dest Unreachable, Bad Code: %d\n",
  729. icp->icmp_code);
  730. break;
  731. }
  732. /* Print returned IP header information */
  733. #ifndef icmp_data
  734. pr_retip(&icp->icmp_ip);
  735. #else
  736. pr_retip((struct ip *)icp->icmp_data);
  737. #endif
  738. break;
  739. case ICMP_SOURCEQUENCH:
  740. (void)printf("Source Quench\n");
  741. #ifndef icmp_data
  742. pr_retip(&icp->icmp_ip);
  743. #else
  744. pr_retip((struct ip *)icp->icmp_data);
  745. #endif
  746. break;
  747. case ICMP_REDIRECT:
  748. switch(icp->icmp_code) {
  749. case ICMP_REDIRECT_NET:
  750. (void)printf("Redirect Network");
  751. break;
  752. case ICMP_REDIRECT_HOST:
  753. (void)printf("Redirect Host");
  754. break;
  755. case ICMP_REDIRECT_TOSNET:
  756. (void)printf("Redirect Type of Service and Network");
  757. break;
  758. case ICMP_REDIRECT_TOSHOST:
  759. (void)printf("Redirect Type of Service and Host");
  760. break;
  761. default:
  762. (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
  763. break;
  764. }
  765. (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
  766. #ifndef icmp_data
  767. pr_retip(&icp->icmp_ip);
  768. #else
  769. pr_retip((struct ip *)icp->icmp_data);
  770. #endif
  771. break;
  772. case ICMP_ECHO:
  773. (void)printf("Echo Request\n");
  774. /* XXX ID + Seq + Data */
  775. break;
  776. case ICMP_TIMXCEED:
  777. switch(icp->icmp_code) {
  778. case ICMP_TIMXCEED_INTRANS:
  779. (void)printf("Time to live exceeded\n");
  780. break;
  781. case ICMP_TIMXCEED_REASS:
  782. (void)printf("Frag reassembly time exceeded\n");
  783. break;
  784. default:
  785. (void)printf("Time exceeded, Bad Code: %d\n",
  786. icp->icmp_code);
  787. break;
  788. }
  789. #ifndef icmp_data
  790. pr_retip(&icp->icmp_ip);
  791. #else
  792. pr_retip((struct ip *)icp->icmp_data);
  793. #endif
  794. break;
  795. case ICMP_PARAMPROB:
  796. (void)printf("Parameter problem: pointer = 0x%02x\n",
  797. icp->icmp_hun.ih_pptr);
  798. #ifndef icmp_data
  799. pr_retip(&icp->icmp_ip);
  800. #else
  801. pr_retip((struct ip *)icp->icmp_data);
  802. #endif
  803. break;
  804. case ICMP_TSTAMP:
  805. (void)printf("Timestamp\n");
  806. /* XXX ID + Seq + 3 timestamps */
  807. break;
  808. case ICMP_TSTAMPREPLY:
  809. (void)printf("Timestamp Reply\n");
  810. /* XXX ID + Seq + 3 timestamps */
  811. break;
  812. case ICMP_IREQ:
  813. (void)printf("Information Request\n");
  814. /* XXX ID + Seq */
  815. break;
  816. case ICMP_IREQREPLY:
  817. (void)printf("Information Reply\n");
  818. /* XXX ID + Seq */
  819. break;
  820. #ifdef ICMP_MASKREQ
  821. case ICMP_MASKREQ:
  822. (void)printf("Address Mask Request\n");
  823. break;
  824. #endif
  825. #ifdef ICMP_MASKREPLY
  826. case ICMP_MASKREPLY:
  827. (void)printf("Address Mask Reply\n");
  828. break;
  829. #endif
  830. default:
  831. (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
  832. }
  833. }
  834. /*
  835. * pr_iph --
  836. * Print an IP header with options.
  837. */
  838. void
  839. pr_iph(ip)
  840. struct ip *ip;
  841. {
  842. int hlen;
  843. u_char *cp;
  844. hlen = ip->ip_hl << 2;
  845. cp = (u_char *)ip + 20; /* point to options */
  846. (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
  847. (void)printf(" %1x %1x %02x %04x %04x",
  848. ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
  849. (void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
  850. (ip->ip_off) & 0x1fff);
  851. (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
  852. (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
  853. (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
  854. /* dump and option bytes */
  855. while (hlen-- > 20)
  856. (void)printf("%02x", *cp++);
  857. (void)putchar('\n');
  858. }
  859. /*
  860. * pr_addr --
  861. * Return an ascii host address as a dotted quad and optionally with
  862. * a hostname.
  863. */
  864. char *
  865. pr_addr(l)
  866. u_long l;
  867. {
  868. struct hostent *hp;
  869. static char buf[80];
  870. if ((options & F_NUMERIC) ||
  871. !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
  872. (void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
  873. else
  874. (void)snprintf(buf, sizeof(buf),
  875. "%s (%s)", hp->h_name, inet_ntoa(*(struct in_addr *)&l));
  876. return (buf);
  877. }
  878. /*
  879. * pr_retip --
  880. * Dump some info on a returned (via ICMP) IP packet.
  881. */
  882. void
  883. pr_retip(ip)
  884. struct ip *ip;
  885. {
  886. int hlen;
  887. u_char *cp;
  888. pr_iph(ip);
  889. hlen = ip->ip_hl << 2;
  890. cp = (u_char *)ip + hlen;
  891. if (ip->ip_p == 6)
  892. (void)printf("TCP: from port %u, to port %u (decimal)\n",
  893. (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  894. else if (ip->ip_p == 17)
  895. (void)printf("UDP: from port %u, to port %u (decimal)\n",
  896. (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  897. }
  898. void
  899. fill(bp, patp)
  900. char *bp, *patp;
  901. {
  902. register int ii, jj, kk;
  903. int pat[16];
  904. char *cp;
  905. for (cp = patp; *cp; cp++)
  906. if (!isxdigit(*cp))
  907. errx(1, "patterns must be specified as hex digits");
  908. ii = sscanf(patp,
  909. "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  910. &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
  911. &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
  912. &pat[13], &pat[14], &pat[15]);
  913. if (ii > 0)
  914. for (kk = 0;
  915. kk <= MAXPACKET - (8 + sizeof(struct timeval) + ii);
  916. kk += ii)
  917. for (jj = 0; jj < ii; ++jj)
  918. bp[jj + kk] = pat[jj];
  919. if (!(options & F_QUIET)) {
  920. (void)printf("PATTERN: 0x");
  921. for (jj = 0; jj < ii; ++jj)
  922. (void)printf("%02x", bp[jj] & 0xFF);
  923. (void)printf("\n");
  924. }
  925. }
  926. void
  927. usage()
  928. {
  929. (void)fprintf(stderr,
  930. "usage: ping [-dfnqRrv] [-c count] [-i wait] [-l preload] [-p pattern]\n\
  931. [-s packetsize] host\n");
  932. exit(1);
  933. }