1 /* $OpenBSD: traceroute.c,v 1.61 2004/01/26 18:23:51 deraadt Exp $ */
2 /* $NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $ */
5 * Copyright (c) 1990, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * $DragonFly: src/usr.sbin/traceroute/traceroute.c,v 1.3 2004/08/27 21:27:41 asmodai Exp $
39 static char copyright[] =
40 "@(#) Copyright (c) 1990, 1993\n\
41 The Regents of the University of California. All rights reserved.\n";
46 static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93";*/
48 static char rcsid[] = "$OpenBSD: traceroute.c,v 1.61 2004/01/26 18:23:51 deraadt Exp $";
53 * traceroute host - trace the route ip packets follow going to "host".
55 * Attempt to trace the route an ip packet would follow to some
56 * internet host. We find out intermediate hops by launching probe
57 * packets with a small ttl (time to live) then listening for an
58 * icmp "time exceeded" reply from a gateway. We start our probes
59 * with a ttl of one and increase by one until we get an icmp "port
60 * unreachable" (which means we got to "host") or hit a max (which
61 * defaults to 64 hops & can be changed with the -m flag). Three
62 * probes (change with -q flag) are sent at each ttl setting and a
63 * line is printed showing the ttl, address of the gateway and
64 * round trip time of each probe. If the probe answers come from
65 * different gateways, the address of each responding system will
66 * be printed. If there is no response within a 5 sec. timeout
67 * interval (changed with the -w flag), a "*" is printed for that
70 * Probe packets are UDP format. We don't want the destination
71 * host to process them so the destination port is set to an
72 * unlikely value (if some clod on the destination is using that
73 * value, it can be changed with the -p flag).
75 * A sample use might be:
77 * [yak 71]% traceroute nis.nsf.net.
78 * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
79 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
80 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
81 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
82 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
83 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
84 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
85 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
86 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
87 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
88 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
89 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
91 * Note that lines 2 & 3 are the same. This is due to a buggy
92 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
93 * packets with a zero ttl.
95 * A more interesting example is:
97 * [yak 72]% traceroute allspice.lcs.mit.edu.
98 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
99 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
100 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
101 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
102 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
103 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
104 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
105 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
106 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
107 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
108 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
109 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
111 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
116 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
118 * (I start to see why I'm having so much trouble with mail to
119 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
120 * either don't send ICMP "time exceeded" messages or send them
121 * with a ttl too small to reach us. 14 - 17 are running the
122 * MIT C Gateway code that doesn't send "time exceeded"s. God
123 * only knows what's going on with 12.
125 * The silent gateway 12 in the above may be the result of a bug in
126 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
127 * sends an unreachable message using whatever ttl remains in the
128 * original datagram. Since, for gateways, the remaining ttl is
129 * zero, the icmp "time exceeded" is guaranteed to not make it back
130 * to us. The behavior of this bug is slightly more interesting
131 * when it appears on the destination system:
133 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
134 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
135 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
136 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
137 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
138 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
145 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
147 * Notice that there are 12 "gateways" (13 is the final
148 * destination) and exactly the last half of them are "missing".
149 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
150 * is using the ttl from our arriving datagram as the ttl in its
151 * icmp reply. So, the reply will time out on the return path
152 * (with no notice sent to anyone since icmp's aren't sent for
153 * icmp's) until we probe with a ttl that's at least twice the path
154 * length. I.e., rip is really only 7 hops away. A reply that
155 * returns with a ttl of 1 is a clue this problem exists.
156 * Traceroute prints a "!" after the time if the ttl is <= 1.
157 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
158 * non-standard (HPUX) software, expect to see this problem
159 * frequently and/or take care picking the target host of your
162 * Other possible annotations after the time are !H, !N, !P (got a host,
163 * network or protocol unreachable, respectively), !S or !F (source
164 * route failed or fragmentation needed -- neither of these should
165 * ever occur and the associated gateway is busted if you see one). If
166 * almost all the probes result in some kind of unreachable, traceroute
167 * will give up and exit.
171 * This program must be run by root or be setuid. (I suggest that
172 * you *don't* make it setuid -- casual use could result in a lot
173 * of unnecessary traffic on our poor, congested nets.)
175 * This program requires a kernel mod that does not appear in any
176 * system available from Berkeley: A raw ip socket using proto
177 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
178 * opposed to data to be wrapped in a ip datagram). See the README
179 * file that came with the source to this program for a description
180 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
181 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
182 * MODIFIED TO RUN THIS PROGRAM.
184 * The udp port usage may appear bizarre (well, ok, it is bizarre).
185 * The problem is that an icmp message only contains 8 bytes of
186 * data from the original datagram. 8 bytes is the size of a udp
187 * header so, if we want to associate replies with the original
188 * datagram, the necessary information must be encoded into the
189 * udp header (the ip id could be used but there's no way to
190 * interlock with the kernel's assignment of ip id's and, anyway,
191 * it would have taken a lot more kernel hacking to allow this
192 * code to set the ip id). So, to allow two or more users to
193 * use traceroute simultaneously, we use this task's pid as the
194 * source port (the high bit is set to move the port number out
195 * of the "likely" range). To keep track of which probe is being
196 * replied to (so times and/or hop counts don't get confused by a
197 * reply that was delayed in transit), we increment the destination
198 * port number before each probe.
200 * Don't use this as a coding example. I was trying to find a
201 * routing problem and this code sort-of popped out after 48 hours
202 * without sleep. I was amazed it ever compiled, much less ran.
204 * I stole the idea for this program from Steve Deering. Since
205 * the first release, I've learned that had I attended the right
206 * IETF working group meetings, I also could have stolen it from Guy
207 * Almes or Matt Mathis. I don't know (or care) who came up with
208 * the idea first. I envy the originators' perspicacity and I'm
209 * glad they didn't keep the idea a secret.
211 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
212 * enhancements to the original distribution.
214 * I've hacked up a round-trip-route version of this that works by
215 * sending a loose-source-routed udp datagram through the destination
216 * back to yourself. Unfortunately, SO many gateways botch source
217 * routing, the thing is almost worthless. Maybe one day...
219 * -- Van Jacobson (van@helios.ee.lbl.gov)
220 * Tue Dec 20 03:50:13 PST 1988
223 #include <sys/param.h>
224 #include <sys/time.h>
225 #include <sys/socket.h>
226 #include <sys/file.h>
227 #include <sys/ioctl.h>
228 #include <sys/sysctl.h>
230 #include <netinet/in_systm.h>
231 #include <netinet/in.h>
232 #include <netinet/ip.h>
233 #include <netinet/ip_icmp.h>
234 #include <netinet/ip_var.h>
235 #include <netinet/udp.h>
237 #include <arpa/inet.h>
248 #define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4)
251 * Format of the data in a (udp) probe packet.
254 u_char seq; /* sequence number of this packet */
255 u_int8_t ttl; /* ttl packet left with */
256 u_int32_t sec; /* time packet left */
260 struct in_addr gateway[MAX_LSRR + 1];
263 int32_t usec_perturb;
265 u_char packet[512], *outpacket; /* last inbound (icmp) packet */
267 void dump_packet(void);
268 int wait_for_reply(int, struct sockaddr_in *, struct timeval *);
269 void send_probe(int, u_int8_t, int, struct sockaddr_in *);
270 int packet_ok(u_char *, int, struct sockaddr_in *, int, int);
271 char *pr_type(u_int8_t);
272 void print(u_char *, int, struct sockaddr_in *);
273 char *inetname(struct in_addr);
274 u_short in_cksum(u_short *, int);
277 int s; /* receive (icmp) socket file descriptor */
278 int sndsock; /* send (udp) socket file descriptor */
280 int datalen; /* How much data */
281 int headerlen; /* How long packet's header is */
287 u_int8_t max_ttl = IPDEFTTL;
288 u_int8_t first_ttl = 1;
290 u_short port = 32768+666; /* start udp dest port # for probe packets */
291 u_char proto = IPPROTO_UDP;
292 u_int8_t icmp_type = ICMP_ECHO; /* default ICMP code/type */
293 u_char icmp_code = 0;
294 int options; /* socket options */
296 int waittime = 5; /* time to wait for response (in seconds) */
297 int nflag; /* print addresses numerically */
301 main(int argc, char *argv[])
303 int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
304 int ttl_flag = 0, incflag = 1, protoset = 0, sump = 0;
305 int ch, i, lsrr = 0, on = 1, probe, seq = 0, tos = 0;
306 size_t size = sizeof(max_ttl);
307 struct sockaddr_in from, to;
315 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
316 err(5, "icmp socket");
317 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
318 err(5, "raw socket");
324 (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &max_ttl, &size,
327 while ((ch = getopt(argc, argv, "SDIdg:f:m:np:q:rs:t:w:vlP:c")) != -1)
335 l = strtol(optarg, &ep, 10);
336 if (errno || !*optarg || *ep || l < 1 || l > max_ttl)
337 errx(1, "min ttl must be 1 to %u.", max_ttl);
338 first_ttl = (u_int8_t)l;
350 if (lsrr >= MAX_LSRR)
351 errx(1, "too many gateways; max %d", MAX_LSRR);
352 if (inet_aton(optarg, &gateway[lsrr]) == 0) {
353 hp = gethostbyname(optarg);
355 errx(1, "unknown host %s", optarg);
356 memcpy(&gateway[lsrr], hp->h_addr, hp->h_length);
364 errx(1, "protocol already set with -P");
366 proto = IPPROTO_ICMP;
374 l = strtol(optarg, &ep, 10);
375 if (errno || !*optarg || *ep || l < first_ttl ||
377 errx(1, "max ttl must be %u to %u.", first_ttl,
379 max_ttl = (u_int8_t)l;
387 l = strtol(optarg, &ep, 10);
388 if (errno || !*optarg || *ep || l <= 0 || l >= 65536)
389 errx(1, "port must be >0, <65536.");
394 errx(1, "protocol already set with -I");
398 l = strtol(optarg, &ep, 10);
399 if (errno || !*optarg || *ep || l < 1 ||
401 struct protoent *pent;
403 pent = getprotobyname(optarg);
405 proto = pent->p_proto;
407 errx(1, "proto must be >=1, or a name.");
414 l = strtol(optarg, &ep, 10);
415 if (errno || !*optarg || *ep || l < 1 || l > INT_MAX)
416 errx(1, "nprobes must be >0.");
420 options |= SO_DONTROUTE;
424 * set the ip source address of the outbound
425 * probe (e.g., on a multi-homed host).
432 l = strtol(optarg, &ep, 10);
433 if (errno || !*optarg || *ep || l < 0 || l > 255)
434 errx(1, "tos must be 0 to 255.");
443 l = strtol(optarg, &ep, 10);
444 if (errno || !*optarg || *ep || l <= 1 || l > INT_MAX)
445 errx(1, "wait must be >1 sec.");
459 (void) memset(&to, 0, sizeof(struct sockaddr));
460 to.sin_family = AF_INET;
461 if (inet_aton(*argv, &to.sin_addr) != 0)
464 hp = gethostbyname(*argv);
466 errx(1, "unknown host %s", *argv);
467 to.sin_family = hp->h_addrtype;
468 memcpy(&to.sin_addr, hp->h_addr, hp->h_length);
469 if ((hostname = strdup(hp->h_name)) == NULL)
471 if (hp->h_addr_list[1] != NULL)
472 warnx("Warning: %s has multiple addresses; using %s",
473 hostname, inet_ntoa(to.sin_addr));
478 l = strtol(*argv, &ep, 10);
479 if (errno || !*argv || *ep || l < 0 || l > INT_MAX)
480 errx(1, "datalen out of range");
486 headerlen = (sizeof(struct ip) + lsrrlen +
487 sizeof(struct udphdr) + sizeof(struct packetdata));
490 headerlen = (sizeof(struct ip) + lsrrlen +
491 sizeof(struct icmp) + sizeof(struct packetdata));
494 headerlen = (sizeof(struct ip) + lsrrlen +
495 sizeof(struct packetdata));
498 if (datalen < 0 || datalen > IP_MAXPACKET - headerlen)
499 errx(1, "packet size must be 0 to %d.",
500 IP_MAXPACKET - headerlen);
502 datalen += headerlen;
504 outpacket = (u_char *)malloc(datalen);
507 (void) memset(outpacket, 0, datalen);
509 ip = (struct ip *)outpacket;
511 u_char *p = (u_char *)(ip + 1);
517 gateway[lsrr] = to.sin_addr;
518 for (i = 1; i <= lsrr; i++) {
519 memcpy(p, &gateway[i], sizeof(struct in_addr));
520 p += sizeof(struct in_addr);
522 ip->ip_dst = gateway[0];
524 ip->ip_dst = to.sin_addr;
525 ip->ip_off = htons(0);
526 ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
528 ip->ip_v = IPVERSION;
531 ident = (getpid() & 0xffff) | 0x8000;
532 tmprnd = arc4random();
533 sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) :
535 usec_perturb = arc4random();
537 if (options & SO_DEBUG)
538 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
539 (char *)&on, sizeof(on));
541 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
542 sizeof(datalen)) < 0)
544 #endif /* SO_SNDBUF */
546 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
548 err(6, "IP_HDRINCL");
549 #endif /* IP_HDRINCL */
550 if (options & SO_DEBUG)
551 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
552 (char *)&on, sizeof(on));
553 if (options & SO_DONTROUTE)
554 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
555 (char *)&on, sizeof(on));
558 (void) memset(&from, 0, sizeof(struct sockaddr));
559 from.sin_family = AF_INET;
560 if (inet_aton(source, &from.sin_addr) == 0)
561 errx(1, "unknown host %s", source);
562 ip->ip_src = from.sin_addr;
564 (ntohl(from.sin_addr.s_addr) & 0xff000000U) == 0x7f000000U &&
565 (ntohl(to.sin_addr.s_addr) & 0xff000000U) != 0x7f000000U)
566 errx(1, "source is on 127/8, destination is not");
569 bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
573 fprintf(stderr, "traceroute to %s (%s)", hostname,
574 inet_ntoa(to.sin_addr));
576 fprintf(stderr, " from %s", source);
577 fprintf(stderr, ", %u hops max, %d byte packets\n", max_ttl, datalen);
578 (void) fflush(stderr);
581 printf("Skipping %u intermediate hops\n", first_ttl - 1);
583 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
584 int got_there = 0, unreachable = 0, timeout = 0, loss;
585 in_addr_t lastaddr = 0;
589 for (probe = 0, loss = 0; probe < nprobes; ++probe) {
591 struct timeval t1, t2;
594 (void) gettimeofday(&t1, NULL);
595 send_probe(++seq, ttl, incflag, &to);
596 while ((cc = wait_for_reply(s, &from, &t1))) {
597 (void) gettimeofday(&t2, NULL);
598 if (t2.tv_sec - t1.tv_sec > waittime) {
602 i = packet_ok(packet, cc, &from, seq, incflag);
603 /* Skip short packet */
606 if (from.sin_addr.s_addr != lastaddr) {
607 print(packet, cc, &from);
608 lastaddr = from.sin_addr.s_addr;
610 dt = (quad_t)(t2.tv_sec - t1.tv_sec) * 1000000 +
611 (quad_t)(t2.tv_usec - t1.tv_usec);
612 printf(" %u", (u_int)(dt / 1000));
614 printf(".%u", (u_int)(dt % 1000));
616 ip = (struct ip *)packet;
618 printf(" (%u)", ip->ip_ttl);
621 ip = (struct ip *)packet;
628 /* time exceeded in transit */
633 case ICMP_UNREACH_PORT:
635 ip = (struct ip *)packet;
641 case ICMP_UNREACH_NET:
645 case ICMP_UNREACH_HOST:
649 case ICMP_UNREACH_PROTOCOL:
653 case ICMP_UNREACH_NEEDFRAG:
657 case ICMP_UNREACH_SRCFAIL:
661 case ICMP_UNREACH_FILTER_PROHIB:
665 case ICMP_UNREACH_NET_PROHIB: /*misuse*/
669 case ICMP_UNREACH_HOST_PROHIB:
673 case ICMP_UNREACH_NET_UNKNOWN:
674 case ICMP_UNREACH_HOST_UNKNOWN:
678 case ICMP_UNREACH_ISOLATED:
682 case ICMP_UNREACH_TOSNET:
683 case ICMP_UNREACH_TOSHOST:
689 printf(" !<%d>", i - 1);
699 (void) fflush(stdout);
702 printf(" (%d%% loss)", (loss * 100) / nprobes);
704 if (got_there || (unreachable && (unreachable + timeout) >= nprobes))
711 wait_for_reply(int sock, struct sockaddr_in *from, struct timeval *sent)
713 socklen_t fromlen = sizeof (*from);
714 struct timeval now, wait;
718 fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask);
719 if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
721 memset(fdsp, 0, fdsn);
723 gettimeofday(&now, NULL);
724 wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec;
725 wait.tv_usec = sent->tv_usec - now.tv_usec;
726 if (wait.tv_usec < 0) {
727 wait.tv_usec += 1000000;
731 wait.tv_sec = wait.tv_usec = 0;
733 if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
734 cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
735 (struct sockaddr *)from, &fromlen);
747 fprintf(stderr, "packet data:");
748 for (p = outpacket, i = 0; i < datalen; i++) {
750 fprintf(stderr, "\n ");
751 fprintf(stderr, " %02x", *p++);
753 fprintf(stderr, "\n");
757 send_probe(int seq, u_int8_t ttl, int iflag, struct sockaddr_in *to)
759 struct ip *ip = (struct ip *)outpacket;
760 u_char *p = (u_char *)(ip + 1);
761 struct udphdr *up = (struct udphdr *)(p + lsrrlen);
762 struct icmp *icmpp = (struct icmp *)(p + lsrrlen);
763 struct packetdata *op;
767 ip->ip_len = htons(datalen);
769 ip->ip_id = htons(ident+seq);
773 icmpp->icmp_type = icmp_type;
774 icmpp->icmp_code = icmp_code;
775 icmpp->icmp_seq = htons(seq);
776 icmpp->icmp_id = htons(ident);
777 op = (struct packetdata *)(icmpp + 1);
780 up->uh_sport = htons(ident);
782 up->uh_dport = htons(port+seq);
784 up->uh_dport = htons(port);
785 up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) -
788 op = (struct packetdata *)(up + 1);
791 op = (struct packetdata *)(ip + 1);
798 * We don't want hostiles snooping the net to get any useful
799 * information about us. Send the timestamp in network byte order,
800 * and perturb the timestamp enough that they won't know our
801 * real clock ticker. We don't want to perturb the time by too
802 * much: being off by a suspiciously large amount might indicate
805 * The timestamps in the packet are currently unused. If future
806 * work wants to use them they will have to subtract out the
807 * perturbation first.
809 (void) gettimeofday(&tv, NULL);
810 op->sec = htonl(tv.tv_sec + sec_perturb);
811 op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000);
813 if (proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) {
814 icmpp->icmp_cksum = 0;
815 icmpp->icmp_cksum = in_cksum((u_short *)icmpp,
816 datalen - sizeof(struct ip) - lsrrlen);
817 if (icmpp->icmp_cksum == 0)
818 icmpp->icmp_cksum = 0xffff;
824 i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
825 sizeof(struct sockaddr_in));
826 if (i < 0 || i != datalen) {
829 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
831 (void) fflush(stdout);
835 static char *ttab[] = {
858 * Convert an ICMP "type" field to a printable string.
864 return ("OUT-OF-RANGE");
869 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq, int iflag)
878 ip = (struct ip *) buf;
879 hlen = ip->ip_hl << 2;
880 if (cc < hlen + ICMP_MINLEN) {
882 printf("packet too short (%d bytes) from %s\n", cc,
883 inet_ntoa(from->sin_addr));
887 icp = (struct icmp *)(buf + hlen);
889 icp = (struct icmp *)buf;
891 type = icp->icmp_type;
892 code = icp->icmp_code;
893 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
894 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
900 hlen = hip->ip_hl << 2;
904 if (icmp_type == ICMP_ECHO &&
905 type == ICMP_ECHOREPLY &&
906 icp->icmp_id == htons(ident) &&
907 icp->icmp_seq == htons(seq))
908 return (-2); /* we got there */
910 icmpp = (struct icmp *)((u_char *)hip + hlen);
911 if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP &&
912 icmpp->icmp_id == htons(ident) &&
913 icmpp->icmp_seq == htons(seq))
914 return (type == ICMP_TIMXCEED? -1 : code + 1);
918 up = (struct udphdr *)((u_char *)hip + hlen);
919 if (hlen + 12 <= cc && hip->ip_p == proto &&
920 up->uh_sport == htons(ident) &&
921 ((iflag && up->uh_dport == htons(port + seq)) ||
922 (!iflag && up->uh_dport == htons(port))))
923 return (type == ICMP_TIMXCEED? -1 : code + 1);
926 /* this is some odd, user specified proto,
927 * how do we check it?
929 if (hip->ip_p == proto)
930 return (type == ICMP_TIMXCEED? -1 : code + 1);
936 in_addr_t *lp = (in_addr_t *)&icp->icmp_ip;
938 printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr));
939 printf(" to %s", inet_ntoa(ip->ip_dst));
940 printf(": icmp type %u (%s) code %d\n", type, pr_type(type),
942 for (i = 4; i < cc ; i += sizeof(in_addr_t))
943 printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++);
950 print(u_char *buf, int cc, struct sockaddr_in *from)
955 ip = (struct ip *) buf;
956 hlen = ip->ip_hl << 2;
960 printf(" %s", inet_ntoa(from->sin_addr));
962 printf(" %s (%s)", inetname(from->sin_addr),
963 inet_ntoa(from->sin_addr));
966 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
971 * Checksum routine for Internet Protocol family headers (C Version)
974 in_cksum(u_short *addr, int len)
976 u_short *w = addr, answer;
977 int nleft = len, sum = 0;
980 * Our algorithm is simple, using a 32 bit accumulator (sum),
981 * we add sequential 16 bit words to it, and at the end, fold
982 * back all the carry bits from the top 16 bits into the lower
990 /* mop up an odd byte, if necessary */
995 * add back carry outs from top 16 bits to low 16 bits
997 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
998 sum += (sum >> 16); /* add carry */
999 answer = ~sum; /* truncate to 16 bits */
1004 * Construct an Internet address representation.
1005 * If the nflag has been supplied, give
1006 * numeric value, otherwise try for symbolic name.
1009 inetname(struct in_addr in)
1011 static char domain[MAXHOSTNAMELEN], line[MAXHOSTNAMELEN];
1012 static int first = 1;
1016 if (first && !nflag) {
1018 if (gethostname(domain, sizeof domain) == 0 &&
1019 (cp = strchr(domain, '.')) != NULL) {
1020 strlcpy(domain, cp + 1, sizeof(domain));
1023 if (!nflag && in.s_addr != INADDR_ANY) {
1024 hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1026 if ((cp = strchr(hp->h_name, '.')) != NULL &&
1027 strcmp(cp + 1, domain) == 0)
1029 strlcpy(line, hp->h_name, sizeof(line));
1033 return (inet_ntoa(in));
1039 extern char *__progname;
1042 "usage: %s [-cdDIlnrSv] [-f first_ttl] [-g gateway_addr] [-m max_ttl]\n"
1043 "\t[-p port] [-P proto] [-q nqueries] [-s src_addr] [-t tos]\n"
1044 "\t[-w waittime] host [packetsize]\n", __progname);