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