Try to pull in PATH_MAX properly
[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 (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
237                     (cp = strchr(domain, '.')))
238                         (void) strcpy(domain, cp + 1);
239                 else
240                         domain[0] = 0;
241         }
242         cp = 0;
243         if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
244                 if(INET_rresolve(name, sizeof(name), from, 0, 0xffffffff) >= 0) {
245                         if ((cp = strchr(name, '.')) &&
246                             !strcmp(cp + 1, domain))
247                                 *cp = 0;
248                         cp = (char *)name;
249                 }
250         }
251         ina = inet_ntoa(from->sin_addr);
252         if (nflag)
253                 printf(" %s", ina);
254         else
255                 printf(" %s (%s)", (cp ? cp : ina), ina);
256 }
257
258 static inline void
259 print(u_char *buf, int cc, struct sockaddr_in *from)
260 {
261         struct ip *ip;
262         int hlen;
263
264         ip = (struct ip *) buf;
265         hlen = ip->ip_hl << 2;
266         cc -= hlen;
267
268         inetname(from);
269 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
270         if (verbose)
271                 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
272 #endif
273 }
274
275 static inline double
276 deltaT(struct timeval *t1p, struct timeval *t2p)
277 {
278         double dt;
279
280         dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
281              (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
282         return (dt);
283 }
284
285 static inline int
286 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
287 {
288         fd_set fds;
289         static struct timeval wait;
290         int cc = 0;
291         int fromlen = sizeof (*from);
292
293         FD_ZERO(&fds);
294         FD_SET(sock, &fds);
295         if (reset_timer) {
296                 /*
297                  * traceroute could hang if someone else has a ping
298                  * running and our ICMP reply gets dropped but we don't
299                  * realize it because we keep waking up to handle those
300                  * other ICMP packets that keep coming in.  To fix this,
301                  * "reset_timer" will only be true if the last packet that
302                  * came in was for us or if this is the first time we're
303                  * waiting for a reply since sending out a probe.  Note
304                  * that this takes advantage of the select() feature on
305                  * Linux where the remaining timeout is written to the
306                  * struct timeval area.
307                  */
308                 wait.tv_sec = waittime;
309                 wait.tv_usec = 0;
310         }
311
312         if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
313                 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
314                             (struct sockaddr *)from, &fromlen);
315
316         return(cc);
317 }
318
319 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
320 /*
321  * Convert an ICMP "type" field to a printable string.
322  */
323 static inline const char *
324 pr_type(t)
325         u_char t;
326 {
327         static const char * const ttab[] = {
328         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
329         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
330         "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
331         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
332         "Info Reply"
333         };
334
335         if(t > 16)
336                 return("OUT-OF-RANGE");
337
338         return(ttab[t]);
339 }
340 #endif
341
342 static inline int
343 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
344 {
345         struct icmp *icp;
346         u_char type, code;
347         int hlen;
348         struct ip *ip;
349
350         ip = (struct ip *) buf;
351         hlen = ip->ip_hl << 2;
352         if (cc < hlen + ICMP_MINLEN) {
353 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
354                 if (verbose)
355                         printf("packet too short (%d bytes) from %s\n", cc,
356                                 inet_ntoa(from->sin_addr));
357 #endif
358                 return (0);
359         }
360         cc -= hlen;
361         icp = (struct icmp *)(buf + hlen);
362         type = icp->icmp_type; code = icp->icmp_code;
363         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
364             type == ICMP_UNREACH) {
365                 struct ip *hip;
366                 struct udphdr *up;
367
368                 hip = &icp->icmp_ip;
369                 hlen = hip->ip_hl << 2;
370                 up = (struct udphdr *)((u_char *)hip + hlen);
371                 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
372                     up->source == htons(ident) &&
373                     up->dest == htons(port+seq))
374                         return (type == ICMP_TIMXCEED? -1 : code+1);
375         }
376 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
377         if (verbose) {
378                 int i;
379                 u_long *lp = (u_long *)&icp->icmp_ip;
380
381                 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
382                         cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
383                         type, pr_type(type), icp->icmp_code);
384                 for (i = 4; i < cc ; i += sizeof(long))
385                         printf("%2d: x%8.8lx\n", i, *lp++);
386         }
387 #endif
388         return(0);
389 }
390
391 static void             /* not inline */
392 send_probe(int seq, int ttl)
393 {
394         struct opacket *op = outpacket;
395         struct ip *ip = &op->ip;
396         struct udphdr *up = &op->udp;
397         int i;
398         struct timezone tz;
399
400         ip->ip_off = 0;
401         ip->ip_hl = sizeof(*ip) >> 2;
402         ip->ip_p = IPPROTO_UDP;
403         ip->ip_len = datalen;
404         ip->ip_ttl = ttl;
405         ip->ip_v = IPVERSION;
406         ip->ip_id = htons(ident+seq);
407
408         up->source = htons(ident);
409         up->dest = htons(port+seq);
410         up->len = htons((u_short)(datalen - sizeof(struct ip)));
411         up->check = 0;
412
413         op->seq = seq;
414         op->ttl = ttl;
415         (void) gettimeofday(&op->tv, &tz);
416
417         i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
418                    sizeof(struct sockaddr));
419         if (i < 0 || i != datalen)  {
420                 if (i<0)
421                         perror("sendto");
422                 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
423                         datalen, i);
424                 (void) fflush(stdout);
425         }
426 }
427
428
429 int
430 #ifndef CONFIG_TRACEROUTE
431 main(argc, argv)
432 #else
433 traceroute_main(argc, argv)
434 #endif
435         int argc;
436         char *argv[];
437 {
438         extern char *optarg;
439         extern int optind;
440         struct hostent *hp;
441         struct sockaddr_in from, *to;
442         int ch, i, on, probe, seq, tos, ttl;
443
444         int options = 0;                /* socket options */
445         char *source = 0;
446         int nprobes = 3;
447
448         on = 1;
449         seq = tos = 0;
450         to = (struct sockaddr_in *)&whereto;
451         while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
452                 switch(ch) {
453                 case 'd':
454 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
455                         options |= SO_DEBUG;
456 #endif
457                         break;
458                 case 'm':
459                         max_ttl = atoi(optarg);
460                         if (max_ttl <= 1)
461                                 error_msg_and_die("max ttl must be >1.");
462                         break;
463                 case 'n':
464                         nflag++;
465                         break;
466                 case 'p':
467                         port = atoi(optarg);
468                         if (port < 1)
469                                 error_msg_and_die("port must be >0.");
470                         break;
471                 case 'q':
472                         nprobes = atoi(optarg);
473                         if (nprobes < 1)
474                                 error_msg_and_die("nprobes must be >0.");
475                         break;
476                 case 'r':
477                         options |= SO_DONTROUTE;
478                         break;
479                 case 's':
480                         /*
481                          * set the ip source address of the outbound
482                          * probe (e.g., on a multi-homed host).
483                          */
484                         source = optarg;
485                         break;
486                 case 't':
487                         tos = atoi(optarg);
488                         if (tos < 0 || tos > 255)
489                                 error_msg_and_die("tos must be 0 to 255.");
490                         break;
491                 case 'v':
492 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
493                         verbose++;
494 #endif
495                         break;
496                 case 'w':
497                         waittime = atoi(optarg);
498                         if (waittime <= 1)
499                                 error_msg_and_die("wait must be >1 sec.");
500                         break;
501                 default:
502                         show_usage();
503                 }
504         argc -= optind;
505         argv += optind;
506
507         if (argc < 1)
508                 show_usage();
509
510         setlinebuf (stdout);
511
512         memset(&whereto, 0, sizeof(struct sockaddr));
513         hp = xgethostbyname(*argv);
514                         to->sin_family = hp->h_addrtype;
515         memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
516                         hostname = (char *)hp->h_name;
517         if (*++argv)
518                 datalen = atoi(*argv);
519         if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
520                 error_msg_and_die("packet size must be 0 <= s < %d.",
521                     MAXPACKET - sizeof(struct opacket));
522         datalen += sizeof(struct opacket);
523         outpacket = (struct opacket *)xmalloc((unsigned)datalen);
524         memset(outpacket, 0, datalen);
525         outpacket->ip.ip_dst = to->sin_addr;
526         outpacket->ip.ip_tos = tos;
527         outpacket->ip.ip_v = IPVERSION;
528         outpacket->ip.ip_id = 0;
529
530         ident = (getpid() & 0xffff) | 0x8000;
531
532         if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
533                 perror_msg_and_die(can_not_create_raw_socket);
534
535         s = create_icmp_socket();
536
537 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
538         if (options & SO_DEBUG)
539                 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
540                                   (char *)&on, sizeof(on));
541 #endif
542         if (options & SO_DONTROUTE)
543                 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
544                                   (char *)&on, sizeof(on));
545 #ifdef SO_SNDBUF
546         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
547                        sizeof(datalen)) < 0)
548                 perror_msg_and_die("SO_SNDBUF");
549 #endif SO_SNDBUF
550 #ifdef IP_HDRINCL
551         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
552                        sizeof(on)) < 0)
553                 perror_msg_and_die("IP_HDRINCL");
554 #endif IP_HDRINCL
555 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
556         if (options & SO_DEBUG)
557                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
558                                   (char *)&on, sizeof(on));
559 #endif
560         if (options & SO_DONTROUTE)
561                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
562                                   (char *)&on, sizeof(on));
563
564         if (source) {
565                 memset(&from, 0, sizeof(struct sockaddr));
566                 from.sin_family = AF_INET;
567                 from.sin_addr.s_addr = inet_addr(source);
568                 if (from.sin_addr.s_addr == -1)
569                         error_msg_and_die("unknown host %s", source);
570                 outpacket->ip.ip_src = from.sin_addr;
571 #ifndef IP_HDRINCL
572                 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
573                         perror_msg_and_die("bind");
574 #endif IP_HDRINCL
575         }
576
577         fprintf(stderr, "traceroute to %s (%s)", hostname,
578                 inet_ntoa(to->sin_addr));
579         if (source)
580                 fprintf(stderr, " from %s", source);
581         fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
582
583         for (ttl = 1; ttl <= max_ttl; ++ttl) {
584                 u_long lastaddr = 0;
585                 int got_there = 0;
586                 int unreachable = 0;
587
588                 printf("%2d ", ttl);
589                 for (probe = 0; probe < nprobes; ++probe) {
590                         int cc, reset_timer;
591                         struct timeval t1, t2;
592                         struct timezone tz;
593                         struct ip *ip;
594
595                         (void) gettimeofday(&t1, &tz);
596                         send_probe(++seq, ttl);
597                         reset_timer = 1;
598                         while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
599                                 (void) gettimeofday(&t2, &tz);
600                                 if ((i = packet_ok(packet, cc, &from, seq))) {
601                                         reset_timer = 1;
602                                         if (from.sin_addr.s_addr != lastaddr) {
603                                                 print(packet, cc, &from);
604                                                 lastaddr = from.sin_addr.s_addr;
605                                         }
606                                         printf("  %g ms", deltaT(&t1, &t2));
607                                         switch(i - 1) {
608                                         case ICMP_UNREACH_PORT:
609                                                 ip = (struct ip *)packet;
610                                                 if (ip->ip_ttl <= 1)
611                                                         printf(" !");
612                                                 ++got_there;
613                                                 break;
614                                         case ICMP_UNREACH_NET:
615                                                 ++unreachable;
616                                                 printf(" !N");
617                                                 break;
618                                         case ICMP_UNREACH_HOST:
619                                                 ++unreachable;
620                                                 printf(" !H");
621                                                 break;
622                                         case ICMP_UNREACH_PROTOCOL:
623                                                 ++got_there;
624                                                 printf(" !P");
625                                                 break;
626                                         case ICMP_UNREACH_NEEDFRAG:
627                                                 ++unreachable;
628                                                 printf(" !F");
629                                                 break;
630                                         case ICMP_UNREACH_SRCFAIL:
631                                                 ++unreachable;
632                                                 printf(" !S");
633                                                 break;
634                                         }
635                                         break;
636                                 } else
637                                         reset_timer = 0;
638                         }
639                         if (cc == 0)
640                                 printf(" *");
641                         (void) fflush(stdout);
642                 }
643                 putchar('\n');
644                 if (got_there || unreachable >= nprobes-1)
645                         return 0;
646         }
647
648         return 0;
649 }