1 #ifndef lint 2 static char *rcsid = 3 "@(#)$Header: traceroute.c,v 1.17 89/02/28 21:01:13 van Exp $ (LBL)"; 4 #endif 5 6 /* 7 * traceroute host - trace the route ip packets follow going to "host". 8 * 9 * Attempt to trace the route an ip packet would follow to some 10 * internet host. We find out intermediate hops by launching probe 11 * packets with a small ttl (time to live) then listening for an 12 * icmp "time exceeded" reply from a gateway. We start our probes 13 * with a ttl of one and increase by one until we get an icmp "port 14 * unreachable" (which means we got to "host") or hit a max (which 15 * defaults to 30 hops & can be changed with the -m flag). Three 16 * probes (change with -q flag) are sent at each ttl setting and a 17 * line is printed showing the ttl, address of the gateway and 18 * round trip time of each probe. If the probe answers come from 19 * different gateways, the address of each responding system will 20 * be printed. If there is no response within a 5 sec. timeout 21 * interval (changed with the -w flag), a "*" is printed for that 22 * probe. 23 * 24 * Probe packets are UDP format. We don't want the destination 25 * host to process them so the destination port is set to an 26 * unlikely value (if some clod on the destination is using that 27 * value, it can be changed with the -p flag). 28 * 29 * A sample use might be: 30 * 31 * [yak 71]% traceroute nis.nsf.net. 32 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 33 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 34 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 35 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 36 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 37 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 38 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 39 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 40 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 41 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 42 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 43 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 44 * 45 * Note that lines 2 & 3 are the same. This is due to a buggy 46 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 47 * packets with a zero ttl. 48 * 49 * A more interesting example is: 50 * 51 * [yak 72]% traceroute allspice.lcs.mit.edu. 52 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 53 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 54 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 55 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 56 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 57 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 58 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 59 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 60 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 61 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 62 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 63 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 64 * 12 * * * 65 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 66 * 14 * * * 67 * 15 * * * 68 * 16 * * * 69 * 17 * * * 70 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 71 * 72 * (I start to see why I'm having so much trouble with mail to 73 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 74 * either don't send ICMP "time exceeded" messages or send them 75 * with a ttl too small to reach us. 14 - 17 are running the 76 * MIT C Gateway code that doesn't send "time exceeded"s. God 77 * only knows what's going on with 12. 78 * 79 * The silent gateway 12 in the above may be the result of a bug in 80 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 81 * sends an unreachable message using whatever ttl remains in the 82 * original datagram. Since, for gateways, the remaining ttl is 83 * zero, the icmp "time exceeded" is guaranteed to not make it back 84 * to us. The behavior of this bug is slightly more interesting 85 * when it appears on the destination system: 86 * 87 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 88 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 89 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 90 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 91 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 92 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 93 * 7 * * * 94 * 8 * * * 95 * 9 * * * 96 * 10 * * * 97 * 11 * * * 98 * 12 * * * 99 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 100 * 101 * Notice that there are 12 "gateways" (13 is the final 102 * destination) and exactly the last half of them are "missing". 103 * What's really happening is that rip (a Sun-3 running Sun OS3.5) 104 * is using the ttl from our arriving datagram as the ttl in its 105 * icmp reply. So, the reply will time out on the return path 106 * (with no notice sent to anyone since icmp's aren't sent for 107 * icmp's) until we probe with a ttl that's at least twice the path 108 * length. I.e., rip is really only 7 hops away. A reply that 109 * returns with a ttl of 1 is a clue this problem exists. 110 * Traceroute prints a "!" after the time if the ttl is <= 1. 111 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 112 * non-standard (HPUX) software, expect to see this problem 113 * frequently and/or take care picking the target host of your 114 * probes. 115 * 116 * Other possible annotations after the time are !H, !N, !P (got a host, 117 * network or protocol unreachable, respectively), !S or !F (source 118 * route failed or fragmentation needed -- neither of these should 119 * ever occur and the associated gateway is busted if you see one). If 120 * almost all the probes result in some kind of unreachable, traceroute 121 * will give up and exit. 122 * 123 * Notes 124 * ----- 125 * This program must be run by root or be setuid. (I suggest that 126 * you *don't* make it setuid -- casual use could result in a lot 127 * of unnecessary traffic on our poor, congested nets.) 128 * 129 * This program requires a kernel mod that does not appear in any 130 * system available from Berkeley: A raw ip socket using proto 131 * IPPROTO_RAW must interpret the data sent as an ip datagram (as 132 * opposed to data to be wrapped in a ip datagram). See the README 133 * file that came with the source to this program for a description 134 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 135 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 136 * MODIFIED TO RUN THIS PROGRAM. 137 * 138 * The udp port usage may appear bizarre (well, ok, it is bizarre). 139 * The problem is that an icmp message only contains 8 bytes of 140 * data from the original datagram. 8 bytes is the size of a udp 141 * header so, if we want to associate replies with the original 142 * datagram, the necessary information must be encoded into the 143 * udp header (the ip id could be used but there's no way to 144 * interlock with the kernel's assignment of ip id's and, anyway, 145 * it would have taken a lot more kernel hacking to allow this 146 * code to set the ip id). So, to allow two or more users to 147 * use traceroute simultaneously, we use this task's pid as the 148 * source port (the high bit is set to move the port number out 149 * of the "likely" range). To keep track of which probe is being 150 * replied to (so times and/or hop counts don't get confused by a 151 * reply that was delayed in transit), we increment the destination 152 * port number before each probe. 153 * 154 * Don't use this as a coding example. I was trying to find a 155 * routing problem and this code sort-of popped out after 48 hours 156 * without sleep. I was amazed it ever compiled, much less ran. 157 * 158 * I stole the idea for this program from Steve Deering. Since 159 * the first release, I've learned that had I attended the right 160 * IETF working group meetings, I also could have stolen it from Guy 161 * Almes or Matt Mathis. I don't know (or care) who came up with 162 * the idea first. I envy the originators' perspicacity and I'm 163 * glad they didn't keep the idea a secret. 164 * 165 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 166 * enhancements to the original distribution. 167 * 168 * I've hacked up a round-trip-route version of this that works by 169 * sending a loose-source-routed udp datagram through the destination 170 * back to yourself. Unfortunately, SO many gateways botch source 171 * routing, the thing is almost worthless. Maybe one day... 172 * 173 * -- Van Jacobson (van@helios.ee.lbl.gov) 174 * Tue Dec 20 03:50:13 PST 1988 175 * 176 * Copyright (c) 1988 Regents of the University of California. 177 * All rights reserved. 178 * 179 * Redistribution and use in source and binary forms are permitted 180 * provided that the above copyright notice and this paragraph are 181 * duplicated in all such forms and that any documentation, 182 * advertising materials, and other materials related to such 183 * distribution and use acknowledge that the software was developed 184 * by the University of California, Berkeley. The name of the 185 * University may not be used to endorse or promote products derived 186 * from this software without specific prior written permission. 187 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 188 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 189 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 190 */ 191 192 #include <stdio.h> 193 #include <errno.h> 194 #include <strings.h> 195 #include <sys/time.h> 196 197 #include <sys/param.h> 198 #include <sys/socket.h> 199 #include <sys/file.h> 200 #include <sys/ioctl.h> 201 202 #include <netinet/in_systm.h> 203 #include <netinet/in.h> 204 #include <netinet/ip.h> 205 #include <netinet/ip_icmp.h> 206 #include <netinet/udp.h> 207 #include <netdb.h> 208 209 #define MAXPACKET 65535 /* max ip packet size */ 210 #ifndef MAXHOSTNAMELEN 211 #define MAXHOSTNAMELEN 64 212 #endif 213 214 #ifndef FD_SET 215 #define NFDBITS (8*sizeof(fd_set)) 216 #define FD_SETSIZE NFDBITS 217 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 218 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 219 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 220 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 221 #endif 222 223 #define Fprintf (void)fprintf 224 #define Sprintf (void)sprintf 225 #define Printf (void)printf 226 extern int errno; 227 extern char *malloc(); 228 extern char *inet_ntoa(); 229 extern u_long inet_addr(); 230 231 /* 232 * format of a (udp) probe packet. 233 */ 234 struct opacket { 235 struct ip ip; 236 struct udphdr udp; 237 u_char seq; /* sequence number of this packet */ 238 u_char ttl; /* ttl packet left with */ 239 struct timeval tv; /* time packet left */ 240 }; 241 242 u_char packet[512]; /* last inbound (icmp) packet */ 243 struct opacket *outpacket; /* last output (udp) packet */ 244 char *inetname(); 245 246 int s; /* receive (icmp) socket file descriptor */ 247 int sndsock; /* send (udp) socket file descriptor */ 248 struct timezone tz; /* leftover */ 249 250 struct sockaddr whereto; /* Who to try to reach */ 251 int datalen; /* How much data */ 252 253 char *source = 0; 254 char *hostname; 255 char hnamebuf[MAXHOSTNAMELEN]; 256 257 int nprobes = 3; 258 int max_ttl = 30; 259 u_short ident; 260 u_short port = 32768+666; /* start udp dest port # for probe packets */ 261 262 int options; /* socket options */ 263 int verbose; 264 int waittime = 5; /* time to wait for response (in seconds) */ 265 int nflag; /* print addresses numerically */ 266 267 char usage[] = 268 "Usage: traceroute [-dnrv] [-w wait] [-m max_ttl] [-p port#] [-q nqueries] [-t tos] [-s src_addr] host [data size]\n"; 269 270 271 main(argc, argv) 272 char *argv[]; 273 { 274 struct sockaddr_in from; 275 char **av = argv; 276 struct sockaddr_in *to = (struct sockaddr_in *) &whereto; 277 int on = 1; 278 struct protoent *pe; 279 int ttl, probe, i; 280 int seq = 0; 281 int tos = 0; 282 struct hostent *hp; 283 284 argc--, av++; 285 while (argc && *av[0] == '-') { 286 while (*++av[0]) 287 switch (*av[0]) { 288 case 'd': 289 options |= SO_DEBUG; 290 break; 291 case 'm': 292 argc--, av++; 293 max_ttl = atoi(av[0]); 294 if (max_ttl <= 1) { 295 Fprintf(stderr, "max ttl must be >1\n"); 296 exit(1); 297 } 298 goto nextarg; 299 case 'n': 300 nflag++; 301 break; 302 case 'p': 303 argc--, av++; 304 port = atoi(av[0]); 305 if (port < 1) { 306 Fprintf(stderr, "port must be >0\n"); 307 exit(1); 308 } 309 goto nextarg; 310 case 'q': 311 argc--, av++; 312 nprobes = atoi(av[0]); 313 if (nprobes < 1) { 314 Fprintf(stderr, "nprobes must be >0\n"); 315 exit(1); 316 } 317 goto nextarg; 318 case 'r': 319 options |= SO_DONTROUTE; 320 break; 321 case 's': 322 /* 323 * set the ip source address of the outbound 324 * probe (e.g., on a multi-homed host). 325 */ 326 argc--, av++; 327 source = av[0]; 328 goto nextarg; 329 case 't': 330 argc--, av++; 331 tos = atoi(av[0]); 332 if (tos < 0 || tos > 255) { 333 Fprintf(stderr, "tos must be 0 to 255\n"); 334 exit(1); 335 } 336 goto nextarg; 337 case 'v': 338 verbose++; 339 break; 340 case 'w': 341 argc--, av++; 342 waittime = atoi(av[0]); 343 if (waittime <= 1) { 344 Fprintf(stderr, "wait must be >1 sec\n"); 345 exit(1); 346 } 347 goto nextarg; 348 } 349 nextarg: 350 argc--, av++; 351 } 352 if (argc < 1) { 353 Printf(usage); 354 exit(1); 355 } 356 setlinebuf (stdout); 357 358 (void) bzero((char *)&whereto, sizeof(struct sockaddr)); 359 to->sin_family = AF_INET; 360 to->sin_addr.s_addr = inet_addr(av[0]); 361 if (to->sin_addr.s_addr != -1) { 362 (void) strcpy(hnamebuf, av[0]); 363 hostname = hnamebuf; 364 } else { 365 hp = gethostbyname(av[0]); 366 if (hp) { 367 to->sin_family = hp->h_addrtype; 368 bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); 369 hostname = hp->h_name; 370 } else { 371 Printf("%s: unknown host %s\n", argv[0], av[0]); 372 exit(1); 373 } 374 } 375 376 if (argc >= 2) 377 datalen = atoi(av[1]); 378 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { 379 Fprintf(stderr, "traceroute: packet size must be 0 <= s < %ld\n", 380 MAXPACKET - sizeof(struct opacket)); 381 exit(1); 382 } 383 datalen += sizeof(struct opacket); 384 outpacket = (struct opacket *)malloc((unsigned)datalen); 385 if (! outpacket) { 386 perror("traceroute: malloc"); 387 exit(1); 388 } 389 (void) bzero((char *)outpacket, datalen); 390 outpacket->ip.ip_dst = to->sin_addr; 391 outpacket->ip.ip_tos = tos; 392 393 ident = (getpid() & 0xffff) | 0x8000; 394 395 if ((pe = getprotobyname("icmp")) == NULL) { 396 Fprintf(stderr, "icmp: unknown protocol\n"); 397 exit(10); 398 } 399 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) { 400 perror("traceroute: icmp socket"); 401 exit(5); 402 } 403 if (options & SO_DEBUG) 404 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 405 (char *)&on, sizeof(on)); 406 if (options & SO_DONTROUTE) 407 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 408 (char *)&on, sizeof(on)); 409 410 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { 411 perror("traceroute: raw socket"); 412 exit(5); 413 } 414 #ifdef SO_SNDBUF 415 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 416 sizeof(datalen)) < 0) { 417 perror("traceroute: SO_SNDBUF"); 418 exit(6); 419 } 420 #endif SO_SNDBUF 421 #ifdef IP_HDRINCL 422 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 423 sizeof(on)) < 0) { 424 perror("traceroute: IP_HDRINCL"); 425 exit(6); 426 } 427 #endif IP_HDRINCL 428 if (options & SO_DEBUG) 429 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 430 (char *)&on, sizeof(on)); 431 if (options & SO_DONTROUTE) 432 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 433 (char *)&on, sizeof(on)); 434 435 if (source) { 436 (void) bzero((char *)&from, sizeof(struct sockaddr)); 437 from.sin_family = AF_INET; 438 from.sin_addr.s_addr = inet_addr(source); 439 if (from.sin_addr.s_addr == -1) { 440 Printf("traceroute: unknown host %s\n", source); 441 exit(1); 442 } 443 outpacket->ip.ip_src = from.sin_addr; 444 #ifndef IP_HDRINCL 445 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) { 446 perror ("traceroute: bind:"); 447 exit (1); 448 } 449 #endif IP_HDRINCL 450 } 451 452 Fprintf(stderr, "traceroute to %s (%s)", hostname, 453 inet_ntoa(to->sin_addr)); 454 if (source) 455 Fprintf(stderr, " from %s", source); 456 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); 457 (void) fflush(stderr); 458 459 for (ttl = 1; ttl <= max_ttl; ++ttl) { 460 u_long lastaddr = 0; 461 int got_there = 0; 462 int unreachable = 0; 463 464 Printf("%2d ", ttl); 465 for (probe = 0; probe < nprobes; ++probe) { 466 int cc; 467 struct timeval tv; 468 struct ip *ip; 469 470 (void) gettimeofday(&tv, &tz); 471 send_probe(++seq, ttl); 472 while (cc = wait_for_reply(s, &from)) { 473 if ((i = packet_ok(packet, cc, &from, seq))) { 474 int dt = deltaT(&tv); 475 if (from.sin_addr.s_addr != lastaddr) { 476 print(packet, cc, &from); 477 lastaddr = from.sin_addr.s_addr; 478 } 479 Printf(" %d ms", dt); 480 switch(i - 1) { 481 case ICMP_UNREACH_PORT: 482 #ifndef ARCHAIC 483 ip = (struct ip *)packet; 484 if (ip->ip_ttl <= 1) 485 Printf(" !"); 486 #endif ARCHAIC 487 ++got_there; 488 break; 489 case ICMP_UNREACH_NET: 490 ++unreachable; 491 Printf(" !N"); 492 break; 493 case ICMP_UNREACH_HOST: 494 ++unreachable; 495 Printf(" !H"); 496 break; 497 case ICMP_UNREACH_PROTOCOL: 498 ++got_there; 499 Printf(" !P"); 500 break; 501 case ICMP_UNREACH_NEEDFRAG: 502 ++unreachable; 503 Printf(" !F"); 504 break; 505 case ICMP_UNREACH_SRCFAIL: 506 ++unreachable; 507 Printf(" !S"); 508 break; 509 } 510 break; 511 } 512 } 513 if (cc == 0) 514 Printf(" *"); 515 (void) fflush(stdout); 516 } 517 putchar('\n'); 518 if (got_there || unreachable >= nprobes-1) 519 exit(0); 520 } 521 } 522 523 wait_for_reply(sock, from) 524 int sock; 525 struct sockaddr_in *from; 526 { 527 fd_set fds; 528 struct timeval wait; 529 int cc = 0; 530 int fromlen = sizeof (*from); 531 532 FD_ZERO(&fds); 533 FD_SET(sock, &fds); 534 wait.tv_sec = waittime; wait.tv_usec = 0; 535 536 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) 537 cc=recvfrom(s, (char *)packet, sizeof(packet), 0, 538 (struct sockaddr *)from, &fromlen); 539 540 return(cc); 541 } 542 543 544 send_probe(seq, ttl) 545 { 546 struct opacket *op = outpacket; 547 struct ip *ip = &op->ip; 548 struct udphdr *up = &op->udp; 549 int i; 550 551 ip->ip_off = 0; 552 ip->ip_p = IPPROTO_UDP; 553 ip->ip_len = datalen; 554 ip->ip_ttl = ttl; 555 556 up->uh_sport = htons(ident); 557 up->uh_dport = htons(port+seq); 558 up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip))); 559 up->uh_sum = 0; 560 561 op->seq = seq; 562 op->ttl = ttl; 563 (void) gettimeofday(&op->tv, &tz); 564 565 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, 566 sizeof(struct sockaddr)); 567 if (i < 0 || i != datalen) { 568 if (i<0) 569 perror("sendto"); 570 Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, 571 datalen, i); 572 (void) fflush(stdout); 573 } 574 } 575 576 577 deltaT(tp) 578 struct timeval *tp; 579 { 580 struct timeval tv; 581 582 (void) gettimeofday(&tv, &tz); 583 tvsub(&tv, tp); 584 return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000); 585 } 586 587 588 /* 589 * Convert an ICMP "type" field to a printable string. 590 */ 591 char * 592 pr_type(t) 593 u_char t; 594 { 595 static char *ttab[] = { 596 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 597 "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 598 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 599 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 600 "Info Reply" 601 }; 602 603 if(t > 16) 604 return("OUT-OF-RANGE"); 605 606 return(ttab[t]); 607 } 608 609 610 packet_ok(buf, cc, from, seq) 611 u_char *buf; 612 int cc; 613 struct sockaddr_in *from; 614 int seq; 615 { 616 register struct icmp *icp; 617 u_char type, code; 618 int hlen; 619 #ifndef ARCHAIC 620 struct ip *ip; 621 622 ip = (struct ip *) buf; 623 hlen = ip->ip_hl << 2; 624 if (cc < hlen + ICMP_MINLEN) { 625 if (verbose) 626 Printf("packet too short (%d bytes) from %s\n", cc, 627 inet_ntoa(from->sin_addr)); 628 return (0); 629 } 630 cc -= hlen; 631 icp = (struct icmp *)(buf + hlen); 632 #else 633 icp = (struct icmp *)buf; 634 #endif ARCHAIC 635 type = icp->icmp_type; code = icp->icmp_code; 636 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 637 type == ICMP_UNREACH) { 638 struct ip *hip; 639 struct udphdr *up; 640 641 hip = &icp->icmp_ip; 642 hlen = hip->ip_hl << 2; 643 up = (struct udphdr *)((u_char *)hip + hlen); 644 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && 645 up->uh_sport == htons(ident) && 646 up->uh_dport == htons(port+seq)) 647 return (type == ICMP_TIMXCEED? -1 : code+1); 648 } 649 #ifndef ARCHAIC 650 if (verbose) { 651 int i; 652 u_long *lp = (u_long *)&icp->icmp_ip; 653 654 Printf("\n%d bytes from %s to %s", cc, 655 inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst)); 656 Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 657 icp->icmp_code); 658 for (i = 4; i < cc ; i += sizeof(long)) 659 Printf("%2d: x%8.8lx\n", i, *lp++); 660 } 661 #endif ARCHAIC 662 return(0); 663 } 664 665 666 print(buf, cc, from) 667 u_char *buf; 668 int cc; 669 struct sockaddr_in *from; 670 { 671 struct ip *ip; 672 int hlen; 673 674 ip = (struct ip *) buf; 675 hlen = ip->ip_hl << 2; 676 cc -= hlen; 677 678 if (nflag) 679 Printf(" %s", inet_ntoa(from->sin_addr)); 680 else 681 Printf(" %s (%s)", inetname(from->sin_addr), 682 inet_ntoa(from->sin_addr)); 683 684 if (verbose) 685 Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 686 } 687 688 689 #ifdef notyet 690 /* 691 * Checksum routine for Internet Protocol family headers (C Version) 692 */ 693 in_cksum(addr, len) 694 u_short *addr; 695 int len; 696 { 697 register int nleft = len; 698 register u_short *w = addr; 699 register u_short answer; 700 register int sum = 0; 701 702 /* 703 * Our algorithm is simple, using a 32 bit accumulator (sum), 704 * we add sequential 16 bit words to it, and at the end, fold 705 * back all the carry bits from the top 16 bits into the lower 706 * 16 bits. 707 */ 708 while (nleft > 1) { 709 sum += *w++; 710 nleft -= 2; 711 } 712 713 /* mop up an odd byte, if necessary */ 714 if (nleft == 1) 715 sum += *(u_char *)w; 716 717 /* 718 * add back carry outs from top 16 bits to low 16 bits 719 */ 720 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 721 sum += (sum >> 16); /* add carry */ 722 answer = ~sum; /* truncate to 16 bits */ 723 return (answer); 724 } 725 #endif notyet 726 727 /* 728 * Subtract 2 timeval structs: out = out - in. 729 * Out is assumed to be >= in. 730 */ 731 tvsub(out, in) 732 register struct timeval *out, *in; 733 { 734 if ((out->tv_usec -= in->tv_usec) < 0) { 735 out->tv_sec--; 736 out->tv_usec += 1000000; 737 } 738 out->tv_sec -= in->tv_sec; 739 } 740 741 742 /* 743 * Construct an Internet address representation. 744 * If the nflag has been supplied, give 745 * numeric value, otherwise try for symbolic name. 746 */ 747 char * 748 inetname(in) 749 struct in_addr in; 750 { 751 register char *cp; 752 static char line[50]; 753 struct hostent *hp; 754 static char domain[MAXHOSTNAMELEN + 1]; 755 static int first = 1; 756 757 if (first && !nflag) { 758 first = 0; 759 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 760 (cp = index(domain, '.'))) 761 (void) strcpy(domain, cp + 1); 762 else 763 domain[0] = 0; 764 } 765 cp = 0; 766 if (!nflag && in.s_addr != INADDR_ANY) { 767 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); 768 if (hp) { 769 if ((cp = index(hp->h_name, '.')) && 770 !strcmp(cp + 1, domain)) 771 *cp = 0; 772 cp = hp->h_name; 773 } 774 } 775 if (cp) 776 (void) strcpy(line, cp); 777 else { 778 in.s_addr = ntohl(in.s_addr); 779 #define C(x) ((x) & 0xff) 780 Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24), 781 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 782 } 783 return (line); 784 } 785