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