Style, error_msg
[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(int argc, char *argv[])
424 #else
425 traceroute_main(int argc, char *argv[])
426 #endif
427 {
428         extern char *optarg;
429         extern int optind;
430         struct hostent *hp;
431         struct sockaddr_in from, *to;
432         int ch, i, on, probe, seq, tos, ttl;
433
434         int options = 0;                /* socket options */
435         char *source = 0;
436         int nprobes = 3;
437
438         on = 1;
439         seq = tos = 0;
440         to = (struct sockaddr_in *)&whereto;
441         while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
442                 switch(ch) {
443                 case 'd':
444 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
445                         options |= SO_DEBUG;
446 #endif
447                         break;
448                 case 'm':
449                         max_ttl = atoi(optarg);
450                         if (max_ttl <= 1)
451                                 error_msg_and_die("max ttl must be >1.");
452                         break;
453                 case 'n':
454                         nflag++;
455                         break;
456                 case 'p':
457                         port = atoi(optarg);
458                         if (port < 1)
459                                 error_msg_and_die("port must be >0.");
460                         break;
461                 case 'q':
462                         nprobes = atoi(optarg);
463                         if (nprobes < 1)
464                                 error_msg_and_die("nprobes must be >0.");
465                         break;
466                 case 'r':
467                         options |= SO_DONTROUTE;
468                         break;
469                 case 's':
470                         /*
471                          * set the ip source address of the outbound
472                          * probe (e.g., on a multi-homed host).
473                          */
474                         source = optarg;
475                         break;
476                 case 't':
477                         tos = atoi(optarg);
478                         if (tos < 0 || tos > 255)
479                                 error_msg_and_die("tos must be 0 to 255.");
480                         break;
481                 case 'v':
482 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
483                         verbose++;
484 #endif
485                         break;
486                 case 'w':
487                         waittime = atoi(optarg);
488                         if (waittime <= 1)
489                                 error_msg_and_die("wait must be >1 sec.");
490                         break;
491                 default:
492                         show_usage();
493                 }
494         argc -= optind;
495         argv += optind;
496
497         if (argc < 1)
498                 show_usage();
499
500         setlinebuf (stdout);
501
502         memset(&whereto, 0, sizeof(struct sockaddr));
503         hp = xgethostbyname(*argv);
504                         to->sin_family = hp->h_addrtype;
505         memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
506                         hostname = (char *)hp->h_name;
507         if (*++argv)
508                 datalen = atoi(*argv);
509         if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
510                 error_msg_and_die("packet size must be 0 <= s < %d.",
511                     MAXPACKET - sizeof(struct opacket));
512         datalen += sizeof(struct opacket);
513         outpacket = (struct opacket *)xmalloc((unsigned)datalen);
514         memset(outpacket, 0, datalen);
515         outpacket->ip.ip_dst = to->sin_addr;
516         outpacket->ip.ip_tos = tos;
517         outpacket->ip.ip_v = IPVERSION;
518         outpacket->ip.ip_id = 0;
519
520         ident = (getpid() & 0xffff) | 0x8000;
521
522         if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
523                 perror_msg_and_die(can_not_create_raw_socket);
524
525         s = create_icmp_socket();
526
527 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
528         if (options & SO_DEBUG)
529                 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
530                                   (char *)&on, sizeof(on));
531 #endif
532         if (options & SO_DONTROUTE)
533                 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
534                                   (char *)&on, sizeof(on));
535 #ifdef SO_SNDBUF
536         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
537                        sizeof(datalen)) < 0)
538                 perror_msg_and_die("SO_SNDBUF");
539 #endif
540 #ifdef IP_HDRINCL
541         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
542                        sizeof(on)) < 0)
543                 perror_msg_and_die("IP_HDRINCL");
544 #endif
545 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
546         if (options & SO_DEBUG)
547                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
548                                   (char *)&on, sizeof(on));
549 #endif
550         if (options & SO_DONTROUTE)
551                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
552                                   (char *)&on, sizeof(on));
553
554         if (source) {
555                 memset(&from, 0, sizeof(struct sockaddr));
556                 from.sin_family = AF_INET;
557                 from.sin_addr.s_addr = inet_addr(source);
558                 if (from.sin_addr.s_addr == -1)
559                         error_msg_and_die("unknown host %s", source);
560                 outpacket->ip.ip_src = from.sin_addr;
561 #ifndef IP_HDRINCL
562                 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
563                         perror_msg_and_die("bind");
564 #endif
565         }
566
567         fprintf(stderr, "traceroute to %s (%s)", hostname,
568                 inet_ntoa(to->sin_addr));
569         if (source)
570                 fprintf(stderr, " from %s", source);
571         fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
572
573         for (ttl = 1; ttl <= max_ttl; ++ttl) {
574                 u_long lastaddr = 0;
575                 int got_there = 0;
576                 int unreachable = 0;
577
578                 printf("%2d ", ttl);
579                 for (probe = 0; probe < nprobes; ++probe) {
580                         int cc, reset_timer;
581                         struct timeval t1, t2;
582                         struct timezone tz;
583                         struct ip *ip;
584
585                         (void) gettimeofday(&t1, &tz);
586                         send_probe(++seq, ttl);
587                         reset_timer = 1;
588                         while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
589                                 (void) gettimeofday(&t2, &tz);
590                                 if ((i = packet_ok(packet, cc, &from, seq))) {
591                                         reset_timer = 1;
592                                         if (from.sin_addr.s_addr != lastaddr) {
593                                                 print(packet, cc, &from);
594                                                 lastaddr = from.sin_addr.s_addr;
595                                         }
596                                         printf("  %g ms", deltaT(&t1, &t2));
597                                         switch(i - 1) {
598                                         case ICMP_UNREACH_PORT:
599                                                 ip = (struct ip *)packet;
600                                                 if (ip->ip_ttl <= 1)
601                                                         printf(" !");
602                                                 ++got_there;
603                                                 break;
604                                         case ICMP_UNREACH_NET:
605                                                 ++unreachable;
606                                                 printf(" !N");
607                                                 break;
608                                         case ICMP_UNREACH_HOST:
609                                                 ++unreachable;
610                                                 printf(" !H");
611                                                 break;
612                                         case ICMP_UNREACH_PROTOCOL:
613                                                 ++got_there;
614                                                 printf(" !P");
615                                                 break;
616                                         case ICMP_UNREACH_NEEDFRAG:
617                                                 ++unreachable;
618                                                 printf(" !F");
619                                                 break;
620                                         case ICMP_UNREACH_SRCFAIL:
621                                                 ++unreachable;
622                                                 printf(" !S");
623                                                 break;
624                                         }
625                                         break;
626                                 } else
627                                         reset_timer = 0;
628                         }
629                         if (cc == 0)
630                                 printf(" *");
631                         (void) fflush(stdout);
632                 }
633                 putchar('\n');
634                 if (got_there || unreachable >= nprobes-1)
635                         return 0;
636         }
637
638         return 0;
639 }