e05a50fbc528b3cbe7ea62b98a67431c891851aa
[oweals/busybox.git] / networking / traceroute.c
1 /*-
2  * Copyright (c) 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Van Jacobson.
7  *
8  * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
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
38 /*
39  * traceroute host  - trace the route ip packets follow going to "host".
40  * Notes
41  * -----
42  * This program must be run by root or be setuid.  (I suggest that
43  * you *don't* make it setuid -- casual use could result in a lot
44  * of unnecessary traffic on our poor, congested nets.)
45  *
46  * I stole the idea for this program from Steve Deering.  Since
47  * the first release, I've learned that had I attended the right
48  * IETF working group meetings, I also could have stolen it from Guy
49  * Almes or Matt Mathis.  I don't know (or care) who came up with
50  * the idea first.  I envy the originators' perspicacity and I'm
51  * glad they didn't keep the idea a secret.
52  *
53  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
54  * enhancements to the original distribution.
55  *
56  * I've hacked up a round-trip-route version of this that works by
57  * sending a loose-source-routed udp datagram through the destination
58  * back to yourself.  Unfortunately, SO many gateways botch source
59  * routing, the thing is almost worthless.  Maybe one day...
60  *
61  *  -- Van Jacobson (van@helios.ee.lbl.gov)
62  *     Tue Dec 20 03:50:13 PST 1988
63  */
64
65 #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
66 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
67 #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG   /* not in documentation man */
68
69 #include <stdio.h>
70 #include <errno.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 #include <sys/time.h>
75 #include "inet_common.h"
76 #include <netdb.h>
77 #include <endian.h>
78 #include <netinet/udp.h>
79 #include <netinet/ip.h>
80 #include <netinet/ip_icmp.h>
81
82  
83  /* It turns out that libc5 doesn't have proper icmp support
84  * built into it header files, so we have to supplement it */
85 #if __GNU_LIBRARY__ < 5
86 static const int ICMP_MINLEN = 8;                               /* abs minimum */
87
88 struct icmp_ra_addr
89 {
90   u_int32_t ira_addr;
91   u_int32_t ira_preference;
92 };
93
94
95 struct icmp
96 {
97   u_int8_t  icmp_type;  /* type of message, see below */
98   u_int8_t  icmp_code;  /* type sub code */
99   u_int16_t icmp_cksum; /* ones complement checksum of struct */
100   union
101   {
102     u_char ih_pptr;             /* ICMP_PARAMPROB */
103     struct in_addr ih_gwaddr;   /* gateway address */
104     struct ih_idseq             /* echo datagram */
105     {
106       u_int16_t icd_id;
107       u_int16_t icd_seq;
108     } ih_idseq;
109     u_int32_t ih_void;
110
111     /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
112     struct ih_pmtu
113     {
114       u_int16_t ipm_void;
115       u_int16_t ipm_nextmtu;
116     } ih_pmtu;
117
118     struct ih_rtradv
119     {
120       u_int8_t irt_num_addrs;
121       u_int8_t irt_wpa;
122       u_int16_t irt_lifetime;
123     } ih_rtradv;
124   } icmp_hun;
125 #define icmp_pptr       icmp_hun.ih_pptr
126 #define icmp_gwaddr     icmp_hun.ih_gwaddr
127 #define icmp_id         icmp_hun.ih_idseq.icd_id
128 #define icmp_seq        icmp_hun.ih_idseq.icd_seq
129 #define icmp_void       icmp_hun.ih_void
130 #define icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
131 #define icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
132 #define icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
133 #define icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
134 #define icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
135   union
136   {
137     struct
138     {
139       u_int32_t its_otime;
140       u_int32_t its_rtime;
141       u_int32_t its_ttime;
142     } id_ts;
143     struct
144     {
145       struct ip idi_ip;
146       /* options and then 64 bits of data */
147     } id_ip;
148     struct icmp_ra_addr id_radv;
149     u_int32_t   id_mask;
150     u_int8_t    id_data[1];
151   } icmp_dun;
152 #define icmp_otime      icmp_dun.id_ts.its_otime
153 #define icmp_rtime      icmp_dun.id_ts.its_rtime
154 #define icmp_ttime      icmp_dun.id_ts.its_ttime
155 #define icmp_ip         icmp_dun.id_ip.idi_ip
156 #define icmp_radv       icmp_dun.id_radv
157 #define icmp_mask       icmp_dun.id_mask
158 #define icmp_data       icmp_dun.id_data
159 };
160
161 #define ICMP_MINLEN     8                               /* abs minimum */
162 #define ICMP_UNREACH            3               /* dest unreachable, codes: */
163 #define ICMP_TIMXCEED           11              /* time exceeded, code: */
164 #define ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
165 #define ICMP_UNREACH_NET                0       /* bad net */
166 #define ICMP_UNREACH_HOST               1       /* bad host */
167 #define ICMP_UNREACH_PROTOCOL           2       /* bad protocol */
168 #define ICMP_UNREACH_PORT               3       /* bad port */
169 #define ICMP_UNREACH_NEEDFRAG           4       /* IP_DF caused drop */
170 #define ICMP_UNREACH_SRCFAIL            5       /* src route failed */
171 #endif
172
173
174 #define MAXPACKET       65535   /* max ip packet size */
175 #ifndef MAXHOSTNAMELEN
176 #define MAXHOSTNAMELEN  64
177 #endif
178
179 /*
180  * format of a (udp) probe packet.
181  */
182 struct opacket {
183         struct ip ip;
184         struct udphdr udp;
185         u_char seq;             /* sequence number of this packet */
186         u_char ttl;             /* ttl packet left with */
187         struct timeval tv;      /* time packet left */
188 };
189
190 /*
191  * Definitions for internet protocol version 4.
192  * Per RFC 791, September 1981.
193  */
194 #define IPVERSION       4
195
196
197 #include "busybox.h"
198
199 static u_char  packet[512];            /* last inbound (icmp) packet */
200 static struct opacket  *outpacket;     /* last output (udp) packet */
201
202 static int s;                          /* receive (icmp) socket file descriptor */
203 static int sndsock;                    /* send (udp) socket file descriptor */
204
205 static struct sockaddr whereto;        /* Who to try to reach */
206 static int datalen;                    /* How much data */
207
208 static char *hostname;
209
210 static int max_ttl = 30;
211 static u_short ident;
212 static u_short port = 32768+666;       /* start udp dest port # for probe packets */
213
214 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
215 static int verbose;
216 #endif
217 static int waittime = 5;               /* time to wait for response (in seconds) */
218 static int nflag;                      /* print addresses numerically */
219
220 /*
221  * Construct an Internet address representation.
222  * If the nflag has been supplied, give
223  * numeric value, otherwise try for symbolic name.
224  */
225 static inline void
226 inetname(struct sockaddr_in *from)
227 {
228         char *cp;
229         static char domain[MAXHOSTNAMELEN + 1];
230         char name[MAXHOSTNAMELEN + 1];
231         static int first = 1;
232         const char *ina;
233
234         if (first && !nflag) {
235                 first = 0;
236                 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
237                         domain[0] = 0;
238         }
239         cp = 0;
240         if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
241                 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
242                         if ((cp = strchr(name, '.')) &&
243                             !strcmp(cp + 1, domain))
244                                 *cp = 0;
245                         cp = (char *)name;
246                 }
247         }
248         ina = inet_ntoa(from->sin_addr);
249         if (nflag)
250                 printf(" %s", ina);
251         else
252                 printf(" %s (%s)", (cp ? cp : ina), ina);
253 }
254
255 static inline void
256 print(u_char *buf, int cc, struct sockaddr_in *from)
257 {
258         struct ip *ip;
259         int hlen;
260
261         ip = (struct ip *) buf;
262         hlen = ip->ip_hl << 2;
263         cc -= hlen;
264
265         inetname(from);
266 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
267         if (verbose)
268                 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
269 #endif
270 }
271
272 static inline double
273 deltaT(struct timeval *t1p, struct timeval *t2p)
274 {
275         double dt;
276
277         dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
278              (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
279         return (dt);
280 }
281
282 static inline int
283 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
284 {
285         fd_set fds;
286         static struct timeval wait;
287         int cc = 0;
288         int fromlen = sizeof (*from);
289
290         FD_ZERO(&fds);
291         FD_SET(sock, &fds);
292         if (reset_timer) {
293                 /*
294                  * traceroute could hang if someone else has a ping
295                  * running and our ICMP reply gets dropped but we don't
296                  * realize it because we keep waking up to handle those
297                  * other ICMP packets that keep coming in.  To fix this,
298                  * "reset_timer" will only be true if the last packet that
299                  * came in was for us or if this is the first time we're
300                  * waiting for a reply since sending out a probe.  Note
301                  * that this takes advantage of the select() feature on
302                  * Linux where the remaining timeout is written to the
303                  * struct timeval area.
304                  */
305                 wait.tv_sec = waittime;
306                 wait.tv_usec = 0;
307         }
308
309         if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
310                 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
311                             (struct sockaddr *)from, &fromlen);
312
313         return(cc);
314 }
315
316 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
317 /*
318  * Convert an ICMP "type" field to a printable string.
319  */
320 static inline const char *
321 pr_type(u_char t)
322 {
323         static const char * const ttab[] = {
324         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
325         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
326         "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
327         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
328         "Info Reply"
329         };
330
331         if(t > 16)
332                 return("OUT-OF-RANGE");
333
334         return(ttab[t]);
335 }
336 #endif
337
338 static inline int
339 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
340 {
341         struct icmp *icp;
342         u_char type, code;
343         int hlen;
344         struct ip *ip;
345
346         ip = (struct ip *) buf;
347         hlen = ip->ip_hl << 2;
348         if (cc < hlen + ICMP_MINLEN) {
349 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
350                 if (verbose)
351                         printf("packet too short (%d bytes) from %s\n", cc,
352                                 inet_ntoa(from->sin_addr));
353 #endif
354                 return (0);
355         }
356         cc -= hlen;
357         icp = (struct icmp *)(buf + hlen);
358         type = icp->icmp_type; code = icp->icmp_code;
359         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
360             type == ICMP_UNREACH) {
361                 struct ip *hip;
362                 struct udphdr *up;
363
364                 hip = &icp->icmp_ip;
365                 hlen = hip->ip_hl << 2;
366                 up = (struct udphdr *)((u_char *)hip + hlen);
367                 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
368                     up->source == htons(ident) &&
369                     up->dest == htons(port+seq))
370                         return (type == ICMP_TIMXCEED? -1 : code+1);
371         }
372 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
373         if (verbose) {
374                 int i;
375                 u_long *lp = (u_long *)&icp->icmp_ip;
376
377                 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
378                         cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
379                         type, pr_type(type), icp->icmp_code);
380                 for (i = 4; i < cc ; i += sizeof(long))
381                         printf("%2d: x%8.8lx\n", i, *lp++);
382         }
383 #endif
384         return(0);
385 }
386
387 static void             /* not inline */
388 send_probe(int seq, int ttl)
389 {
390         struct opacket *op = outpacket;
391         struct ip *ip = &op->ip;
392         struct udphdr *up = &op->udp;
393         int i;
394         struct timezone tz;
395
396         ip->ip_off = 0;
397         ip->ip_hl = sizeof(*ip) >> 2;
398         ip->ip_p = IPPROTO_UDP;
399         ip->ip_len = datalen;
400         ip->ip_ttl = ttl;
401         ip->ip_v = IPVERSION;
402         ip->ip_id = htons(ident+seq);
403
404         up->source = htons(ident);
405         up->dest = htons(port+seq);
406         up->len = htons((u_short)(datalen - sizeof(struct ip)));
407         up->check = 0;
408
409         op->seq = seq;
410         op->ttl = ttl;
411         (void) gettimeofday(&op->tv, &tz);
412
413         i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
414                    sizeof(struct sockaddr));
415         if (i < 0 || i != datalen)  {
416                 if (i<0)
417                         perror("sendto");
418                 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
419                         datalen, i);
420                 (void) fflush(stdout);
421         }
422 }
423
424
425 int
426 #ifndef CONFIG_TRACEROUTE
427 main(argc, argv)
428 #else
429 traceroute_main(argc, argv)
430 #endif
431         int argc;
432         char *argv[];
433 {
434         extern char *optarg;
435         extern int optind;
436         struct hostent *hp;
437         struct sockaddr_in from, *to;
438         int ch, i, on, probe, seq, tos, ttl;
439
440         int options = 0;                /* socket options */
441         char *source = 0;
442         int nprobes = 3;
443
444         on = 1;
445         seq = tos = 0;
446         to = (struct sockaddr_in *)&whereto;
447         while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
448                 switch(ch) {
449                 case 'd':
450 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
451                         options |= SO_DEBUG;
452 #endif
453                         break;
454                 case 'm':
455                         max_ttl = atoi(optarg);
456                         if (max_ttl <= 1)
457                                 error_msg_and_die("max ttl must be >1.");
458                         break;
459                 case 'n':
460                         nflag++;
461                         break;
462                 case 'p':
463                         port = atoi(optarg);
464                         if (port < 1)
465                                 error_msg_and_die("port must be >0.");
466                         break;
467                 case 'q':
468                         nprobes = atoi(optarg);
469                         if (nprobes < 1)
470                                 error_msg_and_die("nprobes must be >0.");
471                         break;
472                 case 'r':
473                         options |= SO_DONTROUTE;
474                         break;
475                 case 's':
476                         /*
477                          * set the ip source address of the outbound
478                          * probe (e.g., on a multi-homed host).
479                          */
480                         source = optarg;
481                         break;
482                 case 't':
483                         tos = atoi(optarg);
484                         if (tos < 0 || tos > 255)
485                                 error_msg_and_die("tos must be 0 to 255.");
486                         break;
487                 case 'v':
488 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
489                         verbose++;
490 #endif
491                         break;
492                 case 'w':
493                         waittime = atoi(optarg);
494                         if (waittime <= 1)
495                                 error_msg_and_die("wait must be >1 sec.");
496                         break;
497                 default:
498                         show_usage();
499                 }
500         argc -= optind;
501         argv += optind;
502
503         if (argc < 1)
504                 show_usage();
505
506         setlinebuf (stdout);
507
508         memset(&whereto, 0, sizeof(struct sockaddr));
509         hp = xgethostbyname(*argv);
510                         to->sin_family = hp->h_addrtype;
511         memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
512                         hostname = (char *)hp->h_name;
513         if (*++argv)
514                 datalen = atoi(*argv);
515         if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
516                 error_msg_and_die("packet size must be 0 <= s < %d.",
517                     MAXPACKET - sizeof(struct opacket));
518         datalen += sizeof(struct opacket);
519         outpacket = (struct opacket *)xmalloc((unsigned)datalen);
520         memset(outpacket, 0, datalen);
521         outpacket->ip.ip_dst = to->sin_addr;
522         outpacket->ip.ip_tos = tos;
523         outpacket->ip.ip_v = IPVERSION;
524         outpacket->ip.ip_id = 0;
525
526         ident = (getpid() & 0xffff) | 0x8000;
527
528         if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
529                 perror_msg_and_die(can_not_create_raw_socket);
530
531         s = create_icmp_socket();
532
533 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
534         if (options & SO_DEBUG)
535                 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
536                                   (char *)&on, sizeof(on));
537 #endif
538         if (options & SO_DONTROUTE)
539                 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
540                                   (char *)&on, sizeof(on));
541 #ifdef SO_SNDBUF
542         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
543                        sizeof(datalen)) < 0)
544                 perror_msg_and_die("SO_SNDBUF");
545 #endif
546 #ifdef IP_HDRINCL
547         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
548                        sizeof(on)) < 0)
549                 perror_msg_and_die("IP_HDRINCL");
550 #endif
551 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
552         if (options & SO_DEBUG)
553                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
554                                   (char *)&on, sizeof(on));
555 #endif
556         if (options & SO_DONTROUTE)
557                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
558                                   (char *)&on, sizeof(on));
559
560         if (source) {
561                 memset(&from, 0, sizeof(struct sockaddr));
562                 from.sin_family = AF_INET;
563                 from.sin_addr.s_addr = inet_addr(source);
564                 if (from.sin_addr.s_addr == -1)
565                         error_msg_and_die("unknown host %s", source);
566                 outpacket->ip.ip_src = from.sin_addr;
567 #ifndef IP_HDRINCL
568                 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
569                         perror_msg_and_die("bind");
570 #endif
571         }
572
573         fprintf(stderr, "traceroute to %s (%s)", hostname,
574                 inet_ntoa(to->sin_addr));
575         if (source)
576                 fprintf(stderr, " from %s", source);
577         fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
578
579         for (ttl = 1; ttl <= max_ttl; ++ttl) {
580                 u_long lastaddr = 0;
581                 int got_there = 0;
582                 int unreachable = 0;
583
584                 printf("%2d ", ttl);
585                 for (probe = 0; probe < nprobes; ++probe) {
586                         int cc, reset_timer;
587                         struct timeval t1, t2;
588                         struct timezone tz;
589                         struct ip *ip;
590
591                         (void) gettimeofday(&t1, &tz);
592                         send_probe(++seq, ttl);
593                         reset_timer = 1;
594                         while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
595                                 (void) gettimeofday(&t2, &tz);
596                                 if ((i = packet_ok(packet, cc, &from, seq))) {
597                                         reset_timer = 1;
598                                         if (from.sin_addr.s_addr != lastaddr) {
599                                                 print(packet, cc, &from);
600                                                 lastaddr = from.sin_addr.s_addr;
601                                         }
602                                         printf("  %g ms", deltaT(&t1, &t2));
603                                         switch(i - 1) {
604                                         case ICMP_UNREACH_PORT:
605                                                 ip = (struct ip *)packet;
606                                                 if (ip->ip_ttl <= 1)
607                                                         printf(" !");
608                                                 ++got_there;
609                                                 break;
610                                         case ICMP_UNREACH_NET:
611                                                 ++unreachable;
612                                                 printf(" !N");
613                                                 break;
614                                         case ICMP_UNREACH_HOST:
615                                                 ++unreachable;
616                                                 printf(" !H");
617                                                 break;
618                                         case ICMP_UNREACH_PROTOCOL:
619                                                 ++got_there;
620                                                 printf(" !P");
621                                                 break;
622                                         case ICMP_UNREACH_NEEDFRAG:
623                                                 ++unreachable;
624                                                 printf(" !F");
625                                                 break;
626                                         case ICMP_UNREACH_SRCFAIL:
627                                                 ++unreachable;
628                                                 printf(" !S");
629                                                 break;
630                                         }
631                                         break;
632                                 } else
633                                         reset_timer = 0;
634                         }
635                         if (cc == 0)
636                                 printf(" *");
637                         (void) fflush(stdout);
638                 }
639                 putchar('\n');
640                 if (got_there || unreachable >= nprobes-1)
641                         return 0;
642         }
643
644         return 0;
645 }