1 /* $NetBSD: traceroute.c,v 1.25 1998/08/27 20:31:02 ross Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #include <sys/cdefs.h> 25 #ifndef lint 26 #if 0 27 static const char rcsid[] = 28 "@(#)Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp (LBL)"; 29 #else 30 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997\n\ 31 The Regents of the University of California. All rights reserved.\n"); 32 __RCSID("$NetBSD: traceroute.c,v 1.25 1998/08/27 20:31:02 ross Exp $"); 33 #endif 34 #endif 35 36 /* 37 * traceroute host - trace the route ip packets follow going to "host". 38 * 39 * Attempt to trace the route an ip packet would follow to some 40 * internet host. We find out intermediate hops by launching probe 41 * packets with a small ttl (time to live) then listening for an 42 * icmp "time exceeded" reply from a gateway. We start our probes 43 * with a ttl of one and increase by one until we get an icmp "port 44 * unreachable" (which means we got to "host") or hit a max (which 45 * defaults to 30 hops & can be changed with the -m flag). Three 46 * probes (change with -q flag) are sent at each ttl setting and a 47 * line is printed showing the ttl, address of the gateway and 48 * round trip time of each probe. If the probe answers come from 49 * different gateways, the address of each responding system will 50 * be printed. If there is no response within a 5 sec. timeout 51 * interval (changed with the -w flag), a "*" is printed for that 52 * probe. 53 * 54 * Probe packets are UDP format. We don't want the destination 55 * host to process them so the destination port is set to an 56 * unlikely value (if some clod on the destination is using that 57 * value, it can be changed with the -p flag). 58 * 59 * A sample use might be: 60 * 61 * [yak 71]% traceroute nis.nsf.net. 62 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 63 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 64 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 65 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 66 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 67 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 68 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 69 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 70 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 71 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 72 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 73 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 74 * 75 * Note that lines 2 & 3 are the same. This is due to a buggy 76 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 77 * packets with a zero ttl. 78 * 79 * A more interesting example is: 80 * 81 * [yak 72]% traceroute allspice.lcs.mit.edu. 82 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 83 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 84 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 85 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 86 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 87 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 88 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 89 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 90 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 91 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 92 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 93 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 94 * 12 * * * 95 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 96 * 14 * * * 97 * 15 * * * 98 * 16 * * * 99 * 17 * * * 100 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 101 * 102 * (I start to see why I'm having so much trouble with mail to 103 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 104 * either don't send ICMP "time exceeded" messages or send them 105 * with a ttl too small to reach us. 14 - 17 are running the 106 * MIT C Gateway code that doesn't send "time exceeded"s. God 107 * only knows what's going on with 12. 108 * 109 * The silent gateway 12 in the above may be the result of a bug in 110 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 111 * sends an unreachable message using whatever ttl remains in the 112 * original datagram. Since, for gateways, the remaining ttl is 113 * zero, the icmp "time exceeded" is guaranteed to not make it back 114 * to us. The behavior of this bug is slightly more interesting 115 * when it appears on the destination system: 116 * 117 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 118 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 119 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 120 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 121 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 122 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 123 * 7 * * * 124 * 8 * * * 125 * 9 * * * 126 * 10 * * * 127 * 11 * * * 128 * 12 * * * 129 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 130 * 131 * Notice that there are 12 "gateways" (13 is the final 132 * destination) and exactly the last half of them are "missing". 133 * What's really happening is that rip (a Sun-3 running Sun OS3.5) 134 * is using the ttl from our arriving datagram as the ttl in its 135 * icmp reply. So, the reply will time out on the return path 136 * (with no notice sent to anyone since icmp's aren't sent for 137 * icmp's) until we probe with a ttl that's at least twice the path 138 * length. I.e., rip is really only 7 hops away. A reply that 139 * returns with a ttl of 1 is a clue this problem exists. 140 * Traceroute prints a "!" after the time if the ttl is <= 1. 141 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 142 * non-standard (HPUX) software, expect to see this problem 143 * frequently and/or take care picking the target host of your 144 * probes. 145 * 146 * Other possible annotations after the time are !H, !N, !P (got a host, 147 * network or protocol unreachable, respectively), !S or !F (source 148 * route failed or fragmentation needed -- neither of these should 149 * ever occur and the associated gateway is busted if you see one). If 150 * almost all the probes result in some kind of unreachable, traceroute 151 * will give up and exit. 152 * 153 * Notes 154 * ----- 155 * This program must be run by root or be setuid. (I suggest that 156 * you *don't* make it setuid -- casual use could result in a lot 157 * of unnecessary traffic on our poor, congested nets.) 158 * 159 * This program requires a kernel mod that does not appear in any 160 * system available from Berkeley: A raw ip socket using proto 161 * IPPROTO_RAW must interpret the data sent as an ip datagram (as 162 * opposed to data to be wrapped in a ip datagram). See the README 163 * file that came with the source to this program for a description 164 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 165 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 166 * MODIFIED TO RUN THIS PROGRAM. 167 * 168 * The udp port usage may appear bizarre (well, ok, it is bizarre). 169 * The problem is that an icmp message only contains 8 bytes of 170 * data from the original datagram. 8 bytes is the size of a udp 171 * header so, if we want to associate replies with the original 172 * datagram, the necessary information must be encoded into the 173 * udp header (the ip id could be used but there's no way to 174 * interlock with the kernel's assignment of ip id's and, anyway, 175 * it would have taken a lot more kernel hacking to allow this 176 * code to set the ip id). So, to allow two or more users to 177 * use traceroute simultaneously, we use this task's pid as the 178 * source port (the high bit is set to move the port number out 179 * of the "likely" range). To keep track of which probe is being 180 * replied to (so times and/or hop counts don't get confused by a 181 * reply that was delayed in transit), we increment the destination 182 * port number before each probe. 183 * 184 * Don't use this as a coding example. I was trying to find a 185 * routing problem and this code sort-of popped out after 48 hours 186 * without sleep. I was amazed it ever compiled, much less ran. 187 * 188 * I stole the idea for this program from Steve Deering. Since 189 * the first release, I've learned that had I attended the right 190 * IETF working group meetings, I also could have stolen it from Guy 191 * Almes or Matt Mathis. I don't know (or care) who came up with 192 * the idea first. I envy the originators' perspicacity and I'm 193 * glad they didn't keep the idea a secret. 194 * 195 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 196 * enhancements to the original distribution. 197 * 198 * I've hacked up a round-trip-route version of this that works by 199 * sending a loose-source-routed udp datagram through the destination 200 * back to yourself. Unfortunately, SO many gateways botch source 201 * routing, the thing is almost worthless. Maybe one day... 202 * 203 * -- Van Jacobson (van@ee.lbl.gov) 204 * Tue Dec 20 03:50:13 PST 1988 205 */ 206 207 #include <sys/param.h> 208 #include <sys/file.h> 209 #include <sys/ioctl.h> 210 #ifdef HAVE_SYS_SELECT_H 211 #include <sys/select.h> 212 #endif 213 #include <sys/socket.h> 214 #include <sys/time.h> 215 216 #include <netinet/in_systm.h> 217 #include <netinet/in.h> 218 #include <netinet/ip.h> 219 #include <netinet/ip_var.h> 220 #include <netinet/ip_icmp.h> 221 #include <netinet/udp.h> 222 #include <netinet/udp_var.h> 223 224 #include <arpa/inet.h> 225 226 #include <ctype.h> 227 #include <errno.h> 228 #ifdef HAVE_MALLOC_H 229 #include <malloc.h> 230 #endif 231 #include <memory.h> 232 #include <netdb.h> 233 #include <stdio.h> 234 #include <stdlib.h> 235 #include <string.h> 236 #include <unistd.h> 237 238 #include "gnuc.h" 239 #ifdef HAVE_OS_PROTO_H 240 #include "os-proto.h" 241 #endif 242 243 #include "ifaddrlist.h" 244 #include "savestr.h" 245 246 /* Maximum number of gateways (include room for one noop) */ 247 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) 248 249 #ifndef MAXHOSTNAMELEN 250 #define MAXHOSTNAMELEN 64 251 #endif 252 253 #define Fprintf (void)fprintf 254 #define Printf (void)printf 255 256 /* Host name and address list */ 257 struct hostinfo { 258 char *name; 259 int n; 260 u_int32_t *addrs; 261 }; 262 263 /* Data section of the probe packet */ 264 struct outdata { 265 u_char seq; /* sequence number of this packet */ 266 u_char ttl; /* ttl packet left with */ 267 struct timeval tv; /* time packet left */ 268 }; 269 270 u_char packet[512]; /* last inbound (icmp) packet */ 271 272 struct ip *outip; /* last output (udp) packet */ 273 struct udphdr *outudp; /* last output (udp) packet */ 274 void *outmark; /* packed location of struct outdata */ 275 struct outdata outsetup; /* setup and copy for alignment */ 276 277 struct icmp *outicmp; /* last output (icmp) packet */ 278 279 /* loose source route gateway list (including room for final destination) */ 280 u_int32_t gwlist[NGATEWAYS + 1]; 281 282 int s; /* receive (icmp) socket file descriptor */ 283 int sndsock; /* send (udp/icmp) socket file descriptor */ 284 285 struct sockaddr whereto; /* Who to try to reach */ 286 struct sockaddr_in wherefrom; /* Who we are */ 287 int packlen; /* total length of packet */ 288 int minpacket; /* min ip packet size */ 289 int maxpacket = 32 * 1024; /* max ip packet size */ 290 291 char *prog; 292 char *source; 293 char *hostname; 294 char *device; 295 296 int nprobes = 3; 297 int max_ttl = 30; 298 int first_ttl = 1; 299 u_short ident; 300 u_short port = 32768 + 666; /* start udp dest port # for probe packets */ 301 302 int options; /* socket options */ 303 int verbose; 304 int waittime = 5; /* time to wait for response (in seconds) */ 305 int nflag; /* print addresses numerically */ 306 int dump; 307 int useicmp; /* use icmp echo instead of udp packets */ 308 #ifdef CANT_HACK_CKSUM 309 int docksum = 0; /* don't calculate checksums */ 310 #else 311 int docksum = 1; /* calculate checksums */ 312 #endif 313 int optlen; /* length of ip options */ 314 315 int mtus[] = { 316 17914, 317 8166, 318 4464, 319 4352, 320 2048, 321 2002, 322 1536, 323 1500, 324 1492, 325 1006, 326 576, 327 552, 328 544, 329 512, 330 508, 331 296, 332 68, 333 0 334 }; 335 int *mtuptr = &mtus[0]; 336 int mtudisc = 0; 337 int nextmtu; /* from ICMP error, set by packet_ok(), might be 0 */ 338 339 extern int optind; 340 extern int opterr; 341 extern char *optarg; 342 343 /* Forwards */ 344 double deltaT(struct timeval *, struct timeval *); 345 void freehostinfo(struct hostinfo *); 346 void getaddr(u_int32_t *, char *); 347 struct hostinfo *gethostinfo(char *); 348 u_short in_cksum(u_short *, int); 349 char *inetname(struct in_addr); 350 int main(int, char **); 351 int packet_ok(u_char *, int, struct sockaddr_in *, int); 352 char *pr_type(u_char); 353 void print(u_char *, int, struct sockaddr_in *); 354 void dump_packet(void); 355 void send_probe(int, int, struct timeval *); 356 void setsin(struct sockaddr_in *, u_int32_t); 357 int str2val(const char *, const char *, int, int); 358 void tvsub(struct timeval *, struct timeval *); 359 __dead void usage(void); 360 int wait_for_reply(int, struct sockaddr_in *, struct timeval *); 361 void frag_err(void); 362 363 364 int 365 main(int argc, char **argv) 366 { 367 register int op, code, n; 368 register char *cp; 369 register u_char *outp; 370 register u_int32_t *ap; 371 register struct sockaddr_in *from = &wherefrom; 372 register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; 373 register struct hostinfo *hi; 374 int on = 1; 375 register struct protoent *pe; 376 register int ttl, probe, i; 377 register int seq = 0; 378 int tos = 0, settos = 0, ttl_flag = 0; 379 register int lsrr = 0; 380 register u_short off = 0; 381 struct ifaddrlist *al; 382 char errbuf[132]; 383 384 if ((cp = strrchr(argv[0], '/')) != NULL) 385 prog = cp + 1; 386 else 387 prog = argv[0]; 388 389 opterr = 0; 390 while ((op = getopt(argc, argv, "dDFPInlrvxf:g:i:m:p:q:s:t:w:")) != -1) 391 switch (op) { 392 393 case 'd': 394 options |= SO_DEBUG; 395 break; 396 397 case 'D': 398 dump = 1; 399 break; 400 401 case 'f': 402 first_ttl = str2val(optarg, "first ttl", 1, 255); 403 break; 404 405 case 'F': 406 off = IP_DF; 407 break; 408 409 case 'g': 410 if (lsrr >= NGATEWAYS) { 411 Fprintf(stderr, 412 "%s: No more than %d gateways\n", 413 prog, NGATEWAYS); 414 exit(1); 415 } 416 getaddr(gwlist + lsrr, optarg); 417 ++lsrr; 418 break; 419 420 case 'i': 421 device = optarg; 422 break; 423 424 case 'I': 425 ++useicmp; 426 break; 427 428 case 'l': 429 ++ttl_flag; 430 break; 431 432 case 'm': 433 max_ttl = str2val(optarg, "max ttl", 1, 255); 434 break; 435 436 case 'n': 437 ++nflag; 438 break; 439 440 case 'p': 441 port = str2val(optarg, "port", 1, -1); 442 break; 443 444 case 'q': 445 nprobes = str2val(optarg, "nprobes", 1, -1); 446 break; 447 448 case 'r': 449 options |= SO_DONTROUTE; 450 break; 451 452 case 's': 453 /* 454 * set the ip source address of the outbound 455 * probe (e.g., on a multi-homed host). 456 */ 457 source = optarg; 458 break; 459 460 case 't': 461 tos = str2val(optarg, "tos", 0, 255); 462 ++settos; 463 break; 464 465 case 'v': 466 ++verbose; 467 break; 468 469 case 'x': 470 docksum = (docksum == 0); 471 break; 472 473 case 'w': 474 waittime = str2val(optarg, "wait time", 2, -1); 475 break; 476 477 case 'P': 478 off = IP_DF; 479 mtudisc = 1; 480 break; 481 482 default: 483 usage(); 484 } 485 486 if (first_ttl > max_ttl) { 487 Fprintf(stderr, 488 "%s: first ttl (%d) may not be greater than max ttl (%d)\n", 489 prog, first_ttl, max_ttl); 490 exit(1); 491 } 492 493 if (!docksum) 494 Fprintf(stderr, "%s: Warning: ckecksums disabled\n", prog); 495 496 if (lsrr > 0) 497 optlen = (lsrr + 1) * sizeof(gwlist[0]); 498 minpacket = sizeof(*outip) + sizeof(struct outdata) + optlen; 499 if (useicmp) 500 minpacket += 8; /* XXX magic number */ 501 else 502 minpacket += sizeof(*outudp); 503 if (packlen == 0) 504 packlen = minpacket; /* minimum sized packet */ 505 else if (minpacket > packlen || packlen > maxpacket) { 506 Fprintf(stderr, "%s: packet size must be %d <= s <= %d\n", 507 prog, minpacket, maxpacket); 508 exit(1); 509 } 510 511 if (mtudisc) 512 packlen = *mtuptr++; 513 514 /* Process destination and optional packet size */ 515 switch (argc - optind) { 516 517 case 2: 518 packlen = str2val(argv[optind + 1], 519 "packet length", minpacket, -1); 520 /* Fall through */ 521 522 case 1: 523 hostname = argv[optind]; 524 hi = gethostinfo(hostname); 525 setsin(to, hi->addrs[0]); 526 if (hi->n > 1) 527 Fprintf(stderr, 528 "%s: Warning: %s has multiple addresses; using %s\n", 529 prog, hostname, inet_ntoa(to->sin_addr)); 530 hostname = hi->name; 531 hi->name = NULL; 532 freehostinfo(hi); 533 break; 534 535 default: 536 usage(); 537 } 538 539 #ifdef HAVE_SETLINEBUF 540 setlinebuf (stdout); 541 #else 542 setvbuf(stdout, NULL, _IOLBF, 0); 543 #endif 544 545 outip = (struct ip *)malloc((unsigned)packlen); 546 if (outip == NULL) { 547 Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); 548 exit(1); 549 } 550 memset((char *)outip, 0, packlen); 551 552 outip->ip_v = IPVERSION; 553 if (settos) 554 outip->ip_tos = tos; 555 #ifdef BYTESWAP_IP_LEN 556 outip->ip_len = htons(packlen); 557 #else 558 outip->ip_len = packlen; 559 #endif 560 outip->ip_off = off; 561 outp = (u_char *)(outip + 1); 562 #ifdef HAVE_RAW_OPTIONS 563 if (lsrr > 0) { 564 register u_char *optlist; 565 566 optlist = outp; 567 outp += optlen; 568 569 /* final hop */ 570 gwlist[lsrr] = to->sin_addr.s_addr; 571 572 outip->ip_dst.s_addr = gwlist[0]; 573 574 /* force 4 byte alignment */ 575 optlist[0] = IPOPT_NOP; 576 /* loose source route option */ 577 optlist[1] = IPOPT_LSRR; 578 i = lsrr * sizeof(gwlist[0]); 579 optlist[2] = i + 3; 580 /* Pointer to LSRR addresses */ 581 optlist[3] = IPOPT_MINOFF; 582 memcpy(optlist + 4, gwlist + 1, i); 583 } else 584 #endif 585 outip->ip_dst = to->sin_addr; 586 587 outip->ip_hl = (outp - (u_char *)outip) >> 2; 588 ident = (getpid() & 0xffff) | 0x8000; 589 if (useicmp) { 590 outip->ip_p = IPPROTO_ICMP; 591 592 outicmp = (struct icmp *)outp; 593 outicmp->icmp_type = ICMP_ECHO; 594 outicmp->icmp_id = htons(ident); 595 596 outmark = outp + 8; /* XXX magic number */ 597 } else { 598 outip->ip_p = IPPROTO_UDP; 599 600 outudp = (struct udphdr *)outp; 601 outudp->uh_sport = htons(ident); 602 outudp->uh_ulen = 603 htons((u_short)(packlen - (sizeof(*outip) + optlen))); 604 outmark = outudp + 1; 605 } 606 607 cp = "icmp"; 608 if ((pe = getprotobyname(cp)) == NULL) { 609 Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 610 exit(1); 611 } 612 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) { 613 Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); 614 exit(1); 615 } 616 if (options & SO_DEBUG) 617 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, 618 sizeof(on)); 619 if (options & SO_DONTROUTE) 620 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 621 sizeof(on)); 622 623 #ifndef __hpux 624 sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 625 #else 626 sndsock = socket(AF_INET, SOCK_RAW, 627 useicmp ? IPPROTO_ICMP : IPPROTO_UDP); 628 #endif 629 if (sndsock < 0) { 630 Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); 631 exit(1); 632 } 633 634 /* Revert to non-privileged user after opening sockets */ 635 setuid(getuid()); 636 637 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) 638 if (lsrr > 0) { 639 u_char optlist[MAX_IPOPTLEN]; 640 641 cp = "ip"; 642 if ((pe = getprotobyname(cp)) == NULL) { 643 Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 644 exit(1); 645 } 646 647 /* final hop */ 648 gwlist[lsrr] = to->sin_addr.s_addr; 649 ++lsrr; 650 651 /* force 4 byte alignment */ 652 optlist[0] = IPOPT_NOP; 653 /* loose source route option */ 654 optlist[1] = IPOPT_LSRR; 655 i = lsrr * sizeof(gwlist[0]); 656 optlist[2] = i + 3; 657 /* Pointer to LSRR addresses */ 658 optlist[3] = IPOPT_MINOFF; 659 memcpy(optlist + 4, gwlist, i); 660 661 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist, 662 i + sizeof(gwlist[0]))) < 0) { 663 Fprintf(stderr, "%s: IP_OPTIONS: %s\n", 664 prog, strerror(errno)); 665 exit(1); 666 } 667 } 668 #endif 669 670 #ifdef SO_SNDBUF 671 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, 672 sizeof(packlen)) < 0) { 673 Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno)); 674 exit(1); 675 } 676 #endif 677 #ifdef IP_HDRINCL 678 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 679 sizeof(on)) < 0) { 680 Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); 681 exit(1); 682 } 683 #else 684 #ifdef IP_TOS 685 if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, 686 (char *)&tos, sizeof(tos)) < 0) { 687 Fprintf(stderr, "%s: setsockopt tos %d: %s\n", 688 prog, tos, strerror(errno)); 689 exit(1); 690 } 691 #endif 692 #endif 693 if (options & SO_DEBUG) 694 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, 695 sizeof(on)); 696 if (options & SO_DONTROUTE) 697 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 698 sizeof(on)); 699 700 /* Get the interface address list */ 701 n = ifaddrlist(&al, errbuf, sizeof errbuf); 702 if (n < 0) { 703 Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); 704 exit(1); 705 } 706 if (n == 0) { 707 Fprintf(stderr, 708 "%s: Can't find any network interfaces\n", prog); 709 exit(1); 710 } 711 712 /* Look for a specific device */ 713 if (device != NULL) { 714 for (i = n; i > 0; --i, ++al) 715 if (strcmp(device, al->device) == 0) 716 break; 717 if (i <= 0) { 718 Fprintf(stderr, "%s: Can't find interface %s\n", 719 prog, device); 720 exit(1); 721 } 722 } 723 724 /* Determine our source address */ 725 if (source == NULL) { 726 /* 727 * If a device was specified, use the interface address. 728 * Otherwise, use the first interface found. 729 * Warn if there are more than one. 730 */ 731 setsin(from, al->addr); 732 if (n > 1 && device == NULL) { 733 Fprintf(stderr, 734 "%s: Warning: Multiple interfaces found; using %s @ %s\n", 735 prog, inet_ntoa(from->sin_addr), al->device); 736 } 737 } else { 738 hi = gethostinfo(source); 739 source = hi->name; 740 hi->name = NULL; 741 if (device == NULL) { 742 /* 743 * Use the first interface found. 744 * Warn if there are more than one. 745 */ 746 setsin(from, hi->addrs[0]); 747 if (hi->n > 1) 748 Fprintf(stderr, 749 "%s: Warning: %s has multiple addresses; using %s\n", 750 prog, source, inet_ntoa(from->sin_addr)); 751 } else { 752 /* 753 * Make sure the source specified matches the 754 * interface address. 755 */ 756 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) 757 if (*ap == al->addr) 758 break; 759 if (i <= 0) { 760 Fprintf(stderr, 761 "%s: %s is not on interface %s\n", 762 prog, source, device); 763 exit(1); 764 } 765 setsin(from, *ap); 766 } 767 freehostinfo(hi); 768 } 769 outip->ip_src = from->sin_addr; 770 #ifndef IP_HDRINCL 771 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { 772 Fprintf(stderr, "%s: bind: %s\n", 773 prog, strerror(errno)); 774 exit (1); 775 } 776 #endif 777 778 setuid(getuid()); 779 Fprintf(stderr, "%s to %s (%s)", 780 prog, hostname, inet_ntoa(to->sin_addr)); 781 if (source) 782 Fprintf(stderr, " from %s", source); 783 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); 784 (void)fflush(stderr); 785 786 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 787 u_int32_t lastaddr = 0; 788 int got_there = 0; 789 int unreachable = 0; 790 791 again: 792 Printf("%2d ", ttl); 793 for (probe = 0; probe < nprobes; ++probe) { 794 register int cc; 795 struct timeval t1, t2; 796 struct timezone tz; 797 register struct ip *ip; 798 (void)gettimeofday(&t1, &tz); 799 send_probe(++seq, ttl, &t1); 800 while ((cc = wait_for_reply(s, from, &t1)) != 0) { 801 (void)gettimeofday(&t2, &tz); 802 /* 803 * Since we'll be receiving all ICMP 804 * messages to this host above, we may 805 * never end up with cc=0, so we need 806 * an additional termination check. 807 */ 808 if (t2.tv_sec - t1.tv_sec > waittime) { 809 cc = 0; 810 break; 811 } 812 i = packet_ok(packet, cc, from, seq); 813 /* Skip short packet */ 814 if (i == 0) 815 continue; 816 if (from->sin_addr.s_addr != lastaddr) { 817 print(packet, cc, from); 818 lastaddr = from->sin_addr.s_addr; 819 } 820 ip = (struct ip *)packet; 821 Printf(" %.3f ms", deltaT(&t1, &t2)); 822 if (ttl_flag) 823 Printf(" (ttl = %d)", ip->ip_ttl); 824 if (i == -2) { 825 #ifndef ARCHAIC 826 if (ip->ip_ttl <= 1) 827 Printf(" !"); 828 #endif 829 ++got_there; 830 break; 831 } 832 833 /* time exceeded in transit */ 834 if (i == -1) 835 break; 836 code = i - 1; 837 switch (code) { 838 839 case ICMP_UNREACH_PORT: 840 #ifndef ARCHAIC 841 if (ip->ip_ttl <= 1) 842 Printf(" !"); 843 #endif 844 ++got_there; 845 break; 846 847 case ICMP_UNREACH_NET: 848 ++unreachable; 849 Printf(" !N"); 850 break; 851 852 case ICMP_UNREACH_HOST: 853 ++unreachable; 854 Printf(" !H"); 855 break; 856 857 case ICMP_UNREACH_PROTOCOL: 858 ++got_there; 859 Printf(" !P"); 860 break; 861 862 case ICMP_UNREACH_NEEDFRAG: 863 if (mtudisc) { 864 frag_err(); 865 goto again; 866 } else { 867 ++unreachable; 868 Printf(" !F"); 869 } 870 break; 871 872 case ICMP_UNREACH_SRCFAIL: 873 ++unreachable; 874 Printf(" !S"); 875 break; 876 877 /* rfc1716 */ 878 #ifndef ICMP_UNREACH_FILTER_PROHIB 879 #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ 880 #endif 881 case ICMP_UNREACH_FILTER_PROHIB: 882 ++unreachable; 883 Printf(" !X"); 884 break; 885 886 default: 887 ++unreachable; 888 Printf(" !<%d>", code); 889 break; 890 } 891 break; 892 } 893 if (cc == 0) 894 Printf(" *"); 895 (void)fflush(stdout); 896 } 897 putchar('\n'); 898 if (got_there || 899 (unreachable > 0 && unreachable >= nprobes)) 900 break; 901 } 902 exit(0); 903 } 904 905 int 906 wait_for_reply(register int sock, register struct sockaddr_in *fromp, 907 register struct timeval *tp) 908 { 909 fd_set fds; 910 struct timeval now, wait; 911 struct timezone tz; 912 register int cc = 0; 913 int fromlen = sizeof(*fromp); 914 915 FD_ZERO(&fds); 916 FD_SET(sock, &fds); 917 918 wait.tv_sec = tp->tv_sec + waittime; 919 wait.tv_usec = tp->tv_usec; 920 (void)gettimeofday(&now, &tz); 921 tvsub(&wait, &now); 922 923 if (select(sock + 1, &fds, NULL, NULL, &wait) > 0) 924 cc = recvfrom(s, (char *)packet, sizeof(packet), 0, 925 (struct sockaddr *)fromp, &fromlen); 926 927 return(cc); 928 } 929 930 void 931 dump_packet() 932 { 933 u_char *p; 934 int i; 935 936 Fprintf(stderr, "packet data:"); 937 938 #ifdef __hpux 939 for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i < 940 i < packlen - (sizeof(*outip) + optlen); i++) 941 #else 942 for (p = (u_char *)outip, i = 0; i < packlen; i++) 943 #endif 944 { 945 if ((i % 24) == 0) 946 Fprintf(stderr, "\n "); 947 Fprintf(stderr, " %02x", *p++); 948 } 949 Fprintf(stderr, "\n"); 950 } 951 952 void 953 send_probe(register int seq, int ttl, register struct timeval *tp) 954 { 955 register int cc; 956 register struct udpiphdr * ui; 957 struct ip tip; 958 959 again: 960 #ifdef BYTESWAP_IP_LEN 961 outip->ip_len = htons(packlen); 962 #else 963 outip->ip_len = packlen; 964 #endif 965 outip->ip_ttl = ttl; 966 #ifndef __hpux 967 outip->ip_id = htons(ident + seq); 968 #endif 969 970 /* 971 * In most cases, the kernel will recalculate the ip checksum. 972 * But we must do it anyway so that the udp checksum comes out 973 * right. 974 */ 975 if (docksum) { 976 outip->ip_sum = 977 in_cksum((u_short *)outip, sizeof(*outip) + optlen); 978 if (outip->ip_sum == 0) 979 outip->ip_sum = 0xffff; 980 } 981 982 /* Payload */ 983 outsetup.seq = seq; 984 outsetup.ttl = ttl; 985 outsetup.tv = *tp; 986 memcpy(outmark,&outsetup,sizeof(outsetup)); 987 988 if (useicmp) 989 outicmp->icmp_seq = htons(seq); 990 else 991 outudp->uh_dport = htons(port + seq); 992 993 /* (We can only do the checksum if we know our ip address) */ 994 if (docksum) { 995 if (useicmp) { 996 outicmp->icmp_cksum = 0; 997 outicmp->icmp_cksum = in_cksum((u_short *)outicmp, 998 packlen - (sizeof(*outip) + optlen)); 999 if (outicmp->icmp_cksum == 0) 1000 outicmp->icmp_cksum = 0xffff; 1001 } else { 1002 /* Checksum (must save and restore ip header) */ 1003 tip = *outip; 1004 ui = (struct udpiphdr *)outip; 1005 #ifndef __NetBSD__ 1006 ui->ui_next = 0; 1007 ui->ui_prev = 0; 1008 ui->ui_x1 = 0; 1009 #else 1010 memset(ui->ui_x1, 0, sizeof(ui->ui_x1)); 1011 #endif 1012 ui->ui_len = outudp->uh_ulen; 1013 outudp->uh_sum = 0; 1014 outudp->uh_sum = in_cksum((u_short *)ui, packlen); 1015 if (outudp->uh_sum == 0) 1016 outudp->uh_sum = 0xffff; 1017 *outip = tip; 1018 } 1019 } 1020 1021 /* XXX undocumented debugging hack */ 1022 if (verbose > 1) { 1023 register const u_short *sp; 1024 register int nshorts, i; 1025 1026 sp = (u_short *)outip; 1027 nshorts = (u_int)packlen / sizeof(u_short); 1028 i = 0; 1029 Printf("[ %d bytes", packlen); 1030 while (--nshorts >= 0) { 1031 if ((i++ % 8) == 0) 1032 Printf("\n\t"); 1033 Printf(" %04x", ntohs(*sp++)); 1034 } 1035 if (packlen & 1) { 1036 if ((i % 8) == 0) 1037 Printf("\n\t"); 1038 Printf(" %02x", *(u_char *)sp); 1039 } 1040 Printf("]\n"); 1041 } 1042 1043 #if !defined(IP_HDRINCL) && defined(IP_TTL) 1044 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, 1045 (char *)&ttl, sizeof(ttl)) < 0) { 1046 Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", 1047 prog, ttl, strerror(errno)); 1048 exit(1); 1049 } 1050 #endif 1051 if (dump) 1052 dump_packet(); 1053 1054 #ifdef __hpux 1055 cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp, 1056 packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto)); 1057 if (cc > 0) 1058 cc += sizeof(*outip) + optlen; 1059 #else 1060 cc = sendto(sndsock, (char *)outip, 1061 packlen, 0, &whereto, sizeof(whereto)); 1062 #endif 1063 if (cc < 0 || cc != packlen) { 1064 if (cc < 0) { 1065 /* 1066 * An errno of EMSGSIZE means we're writing too big a 1067 * datagram for the interface. We have to just decrease 1068 * the packet size until we find one that works. 1069 * 1070 * XXX maybe we should try to read the outgoing if's 1071 * mtu? 1072 */ 1073 1074 if (errno == EMSGSIZE) { 1075 packlen = *mtuptr++; 1076 #ifdef _NoLongerLooksUgly_ 1077 Printf("\nmessage too big, " 1078 "trying new MTU = %d ", packlen); 1079 #endif 1080 goto again; 1081 } else 1082 Fprintf(stderr, "%s: sendto: %s\n", 1083 prog, strerror(errno)); 1084 } 1085 1086 Printf("%s: wrote %s %d chars, ret=%d\n", 1087 prog, hostname, packlen, cc); 1088 (void)fflush(stdout); 1089 } 1090 } 1091 1092 double 1093 deltaT(struct timeval *t1p, struct timeval *t2p) 1094 { 1095 register double dt; 1096 1097 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 1098 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 1099 return (dt); 1100 } 1101 1102 /* 1103 * Convert an ICMP "type" field to a printable string. 1104 */ 1105 char * 1106 pr_type(register u_char t) 1107 { 1108 static char *ttab[] = { 1109 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 1110 "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 1111 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 1112 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 1113 "Info Reply" 1114 }; 1115 1116 if (t > 16) 1117 return("OUT-OF-RANGE"); 1118 1119 return(ttab[t]); 1120 } 1121 1122 int 1123 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from, 1124 register int seq) 1125 { 1126 register struct icmp *icp; 1127 register u_char type, code; 1128 register int hlen; 1129 #ifndef ARCHAIC 1130 register struct ip *ip; 1131 1132 ip = (struct ip *) buf; 1133 hlen = ip->ip_hl << 2; 1134 if (cc < hlen + ICMP_MINLEN) { 1135 if (verbose) 1136 Printf("packet too short (%d bytes) from %s\n", cc, 1137 inet_ntoa(from->sin_addr)); 1138 return (0); 1139 } 1140 cc -= hlen; 1141 icp = (struct icmp *)(buf + hlen); 1142 #else 1143 icp = (struct icmp *)buf; 1144 #endif 1145 type = icp->icmp_type; 1146 code = icp->icmp_code; 1147 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 1148 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { 1149 register struct ip *hip; 1150 register struct udphdr *up; 1151 register struct icmp *hicmp; 1152 1153 hip = &icp->icmp_ip; 1154 hlen = hip->ip_hl << 2; 1155 1156 nextmtu = icp->icmp_nextmtu; /* for frag_err() */ 1157 1158 if (useicmp) { 1159 /* XXX */ 1160 if (type == ICMP_ECHOREPLY && 1161 icp->icmp_id == htons(ident) && 1162 icp->icmp_seq == htons(seq)) 1163 return (-2); 1164 1165 hicmp = (struct icmp *)((u_char *)hip + hlen); 1166 /* XXX 8 is a magic number */ 1167 if (hlen + 8 <= cc && 1168 hip->ip_p == IPPROTO_ICMP && 1169 hicmp->icmp_id == htons(ident) && 1170 hicmp->icmp_seq == htons(seq)) 1171 return (type == ICMP_TIMXCEED ? -1 : code + 1); 1172 } else { 1173 up = (struct udphdr *)((u_char *)hip + hlen); 1174 /* XXX 8 is a magic number */ 1175 if (hlen + 12 <= cc && 1176 hip->ip_p == IPPROTO_UDP && 1177 up->uh_sport == htons(ident) && 1178 up->uh_dport == htons(port + seq)) 1179 return (type == ICMP_TIMXCEED ? -1 : code + 1); 1180 } 1181 } 1182 #ifndef ARCHAIC 1183 if (verbose) { 1184 register int i; 1185 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip; 1186 1187 Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr)); 1188 Printf("%s: icmp type %d (%s) code %d\n", 1189 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); 1190 for (i = 4; i < cc ; i += sizeof(*lp)) 1191 Printf("%2d: x%8.8x\n", i, *lp++); 1192 } 1193 #endif 1194 return(0); 1195 } 1196 1197 1198 void 1199 print(register u_char *buf, register int cc, register struct sockaddr_in *from) 1200 { 1201 register struct ip *ip; 1202 register int hlen; 1203 1204 ip = (struct ip *) buf; 1205 hlen = ip->ip_hl << 2; 1206 cc -= hlen; 1207 1208 if (nflag) 1209 Printf(" %s", inet_ntoa(from->sin_addr)); 1210 else 1211 Printf(" %s (%s)", inetname(from->sin_addr), 1212 inet_ntoa(from->sin_addr)); 1213 1214 if (verbose) 1215 Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 1216 } 1217 1218 /* 1219 * Checksum routine for Internet Protocol family headers (C Version) 1220 */ 1221 u_short 1222 in_cksum(register u_short *addr, register int len) 1223 { 1224 register int nleft = len; 1225 register u_short *w = addr; 1226 register u_short answer; 1227 register int sum = 0; 1228 1229 /* 1230 * Our algorithm is simple, using a 32 bit accumulator (sum), 1231 * we add sequential 16 bit words to it, and at the end, fold 1232 * back all the carry bits from the top 16 bits into the lower 1233 * 16 bits. 1234 */ 1235 while (nleft > 1) { 1236 sum += *w++; 1237 nleft -= 2; 1238 } 1239 1240 /* mop up an odd byte, if necessary */ 1241 if (nleft == 1) 1242 sum += *(u_char *)w; 1243 1244 /* 1245 * add back carry outs from top 16 bits to low 16 bits 1246 */ 1247 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 1248 sum += (sum >> 16); /* add carry */ 1249 answer = ~sum; /* truncate to 16 bits */ 1250 return (answer); 1251 } 1252 1253 /* 1254 * Subtract 2 timeval structs: out = out - in. 1255 * Out is assumed to be >= in. 1256 */ 1257 void 1258 tvsub(register struct timeval *out, register struct timeval *in) 1259 { 1260 1261 if ((out->tv_usec -= in->tv_usec) < 0) { 1262 --out->tv_sec; 1263 out->tv_usec += 1000000; 1264 } 1265 out->tv_sec -= in->tv_sec; 1266 } 1267 1268 /* 1269 * Construct an Internet address representation. 1270 * If the nflag has been supplied, give 1271 * numeric value, otherwise try for symbolic name. 1272 */ 1273 char * 1274 inetname(struct in_addr in) 1275 { 1276 register char *cp; 1277 register struct hostent *hp; 1278 static int first = 1; 1279 static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1]; 1280 1281 if (first && !nflag) { 1282 int rv; 1283 1284 first = 0; 1285 rv = gethostname(domain, sizeof domain); 1286 domain[sizeof(domain) - 1] = '\0'; 1287 if (rv == 0 && (cp = strchr(domain, '.')) != NULL) { 1288 (void)strncpy(domain, cp + 1, sizeof(domain) - 1); 1289 } else 1290 domain[0] = '\0'; 1291 } 1292 if (!nflag && in.s_addr != INADDR_ANY) { 1293 hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); 1294 if (hp != NULL) { 1295 if ((cp = strchr(hp->h_name, '.')) != NULL && 1296 strcmp(cp + 1, domain) == 0) 1297 *cp = '\0'; 1298 (void)strncpy(line, hp->h_name, sizeof(line) - 1); 1299 line[sizeof(line) - 1] = '\0'; 1300 return (line); 1301 } 1302 } 1303 return (inet_ntoa(in)); 1304 } 1305 1306 struct hostinfo * 1307 gethostinfo(register char *hostname) 1308 { 1309 register int n; 1310 register struct hostent *hp; 1311 register struct hostinfo *hi; 1312 register char **p; 1313 register u_int32_t *ap; 1314 struct in_addr addr; 1315 1316 hi = calloc(1, sizeof(*hi)); 1317 if (hi == NULL) { 1318 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1319 exit(1); 1320 } 1321 if (inet_aton(hostname, &addr) != 0) { 1322 hi->name = savestr(hostname); 1323 hi->n = 1; 1324 hi->addrs = calloc(1, sizeof(hi->addrs[0])); 1325 if (hi->addrs == NULL) { 1326 Fprintf(stderr, "%s: calloc %s\n", 1327 prog, strerror(errno)); 1328 exit(1); 1329 } 1330 hi->addrs[0] = addr.s_addr; 1331 return (hi); 1332 } 1333 1334 hp = gethostbyname(hostname); 1335 if (hp == NULL) { 1336 Fprintf(stderr, "%s: unknown host %s\n", prog, hostname); 1337 exit(1); 1338 } 1339 if (hp->h_addrtype != AF_INET || hp->h_length != 4) { 1340 Fprintf(stderr, "%s: bad host %s\n", prog, hostname); 1341 exit(1); 1342 } 1343 hi->name = savestr(hp->h_name); 1344 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) 1345 continue; 1346 hi->n = n; 1347 hi->addrs = calloc(n, sizeof(hi->addrs[0])); 1348 if (hi->addrs == NULL) { 1349 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1350 exit(1); 1351 } 1352 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) 1353 memcpy(ap, *p, sizeof(*ap)); 1354 return (hi); 1355 } 1356 1357 void 1358 freehostinfo(register struct hostinfo *hi) 1359 { 1360 if (hi->name != NULL) { 1361 free(hi->name); 1362 hi->name = NULL; 1363 } 1364 free((char *)hi->addrs); 1365 free((char *)hi); 1366 } 1367 1368 void 1369 getaddr(register u_int32_t *ap, register char *hostname) 1370 { 1371 register struct hostinfo *hi; 1372 1373 hi = gethostinfo(hostname); 1374 *ap = hi->addrs[0]; 1375 freehostinfo(hi); 1376 } 1377 1378 void 1379 setsin(register struct sockaddr_in *sin, register u_int32_t addr) 1380 { 1381 1382 memset(sin, 0, sizeof(*sin)); 1383 #ifdef HAVE_SOCKADDR_SA_LEN 1384 sin->sin_len = sizeof(*sin); 1385 #endif 1386 sin->sin_family = AF_INET; 1387 sin->sin_addr.s_addr = addr; 1388 } 1389 1390 /* String to value with optional min and max. Handles decimal and hex. */ 1391 int 1392 str2val(register const char *str, register const char *what, 1393 register int mi, register int ma) 1394 { 1395 register const char *cp; 1396 register int val; 1397 char *ep; 1398 1399 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 1400 cp = str + 2; 1401 val = (int)strtol(cp, &ep, 16); 1402 } else 1403 val = (int)strtol(str, &ep, 10); 1404 if (*ep != '\0') { 1405 Fprintf(stderr, "%s: \"%s\" bad value for %s \n", 1406 prog, str, what); 1407 exit(1); 1408 } 1409 if (val < mi && mi >= 0) { 1410 if (mi == 0) 1411 Fprintf(stderr, "%s: %s must be >= %d\n", 1412 prog, what, mi); 1413 else 1414 Fprintf(stderr, "%s: %s must be > %d\n", 1415 prog, what, mi - 1); 1416 exit(1); 1417 } 1418 if (val > ma && ma >= 0) { 1419 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); 1420 exit(1); 1421 } 1422 return (val); 1423 } 1424 1425 __dead void 1426 usage(void) 1427 { 1428 extern char version[]; 1429 1430 Fprintf(stderr, "Version %s\n", version); 1431 Fprintf(stderr, "Usage: %s [-dDFPIlnrvx] [-g gateway] [-i iface] \ 1432 [-f first_ttl] [-m max_ttl]\n\t[ -p port] [-q nqueries] [-s src_addr] [-t tos] \ 1433 [-w waittime]\n\thost [packetlen]\n", 1434 prog); 1435 exit(1); 1436 } 1437 1438 /* 1439 * Received ICMP unreachable (fragmentation required and DF set). 1440 * If the ICMP error was from a "new" router, it'll contain the next-hop 1441 * MTU that we should use next. Otherwise we'll just keep going in the 1442 * mtus[] table, trying until we hit a valid MTU. 1443 */ 1444 1445 1446 void 1447 frag_err() 1448 { 1449 int i; 1450 1451 if (nextmtu > 0) { 1452 Printf("\nfragmentation required and DF set, next hop MTU = %d\n 1453 ", 1454 nextmtu); 1455 packlen = nextmtu; 1456 for (i = 0; mtus[i] > 0; i++) { 1457 if (mtus[i] < nextmtu) { 1458 mtuptr = &mtus[i]; /* next one to try */ 1459 return; 1460 } 1461 } 1462 } else { 1463 packlen = *mtuptr++; 1464 Printf("fragmentation required and DF set, " 1465 "trying new MTU = %d ", packlen); 1466 } 1467 } 1468 1469