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