1 /* $OpenBSD: traceroute.c,v 1.95 2014/03/24 11:11:49 mpi Exp $ */ 2 /* $NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $ */ 3 4 /*- 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Van Jacobson. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 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 64 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), 64 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), 64 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@helios.ee.lbl.gov) 204 * Tue Dec 20 03:50:13 PST 1988 205 */ 206 207 #include <sys/param.h> 208 #include <sys/time.h> 209 #include <sys/socket.h> 210 #include <sys/file.h> 211 #include <sys/ioctl.h> 212 #include <sys/sysctl.h> 213 214 #include <netinet/in_systm.h> 215 #include <netinet/in.h> 216 #include <netinet/ip.h> 217 #include <netinet/ip_icmp.h> 218 #include <netinet/ip_var.h> 219 #include <netinet/udp.h> 220 221 #include <arpa/inet.h> 222 #include <arpa/nameser.h> 223 224 #include <netmpls/mpls.h> 225 226 #include <ctype.h> 227 #include <err.h> 228 #include <errno.h> 229 #include <netdb.h> 230 #include <stdio.h> 231 #include <stdlib.h> 232 #include <string.h> 233 #include <unistd.h> 234 235 #define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4) 236 237 #define MPLS_LABEL(m) ((m & MPLS_LABEL_MASK) >> MPLS_LABEL_OFFSET) 238 #define MPLS_EXP(m) ((m & MPLS_EXP_MASK) >> MPLS_EXP_OFFSET) 239 240 /* 241 * Format of the data in a (udp) probe packet. 242 */ 243 struct packetdata { 244 u_char seq; /* sequence number of this packet */ 245 u_int8_t ttl; /* ttl packet left with */ 246 u_char pad[2]; 247 u_int32_t sec; /* time packet left */ 248 u_int32_t usec; 249 } __packed; 250 251 struct in_addr gateway[MAX_LSRR + 1]; 252 int lsrrlen = 0; 253 int32_t sec_perturb; 254 int32_t usec_perturb; 255 256 u_char packet[512], *outpacket; /* last inbound (icmp) packet */ 257 258 int wait_for_reply(int, struct sockaddr_in *, struct timeval *); 259 void dump_packet(void); 260 void send_probe(int, u_int8_t, int, struct sockaddr_in *); 261 int packet_ok(u_char *, int, struct sockaddr_in *, int, int); 262 void dump_packet(void); 263 void print_exthdr(u_char *, int); 264 void print(struct sockaddr *, int, const char *); 265 const char *inetname(struct sockaddr*); 266 void print_asn(struct sockaddr_storage *); 267 u_short in_cksum(u_short *, int); 268 char *pr_type(u_int8_t); 269 int map_tos(char *, int *); 270 void usage(void); 271 272 int rcvsock; /* receive (icmp) socket file descriptor */ 273 int sndsock; /* send (udp) socket file descriptor */ 274 275 int datalen; /* How much data */ 276 int headerlen; /* How long packet's header is */ 277 278 char *source = 0; 279 char *hostname; 280 281 int nprobes = 3; 282 u_int8_t max_ttl = IPDEFTTL; 283 u_int8_t first_ttl = 1; 284 u_short ident; 285 u_int16_t port = 32768+666; /* start udp dest port # for probe packets */ 286 u_char proto = IPPROTO_UDP; 287 u_int8_t icmp_type = ICMP_ECHO; /* default ICMP code/type */ 288 u_char icmp_code = 0; 289 int options; /* socket options */ 290 int verbose; 291 int waittime = 5; /* time to wait for response (in seconds) */ 292 int nflag; /* print addresses numerically */ 293 int dump; 294 int xflag; /* show ICMP extension header */ 295 int tflag; /* tos flag was set */ 296 int Aflag; /* lookup ASN */ 297 298 int 299 main(int argc, char *argv[]) 300 { 301 int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; 302 int ttl_flag = 0, incflag = 1, protoset = 0, sump = 0; 303 int ch, i, lsrr = 0, on = 1, probe, seq = 0, tos = 0; 304 int last_tos, tos_returned; 305 size_t size = sizeof(max_ttl); 306 struct sockaddr_in from, to; 307 struct hostent *hp; 308 u_int32_t tmprnd; 309 struct ip *ip, *inner_ip; 310 struct icmp *icp; 311 u_int8_t ttl; 312 char *ep, hbuf[NI_MAXHOST]; 313 const char *errstr; 314 long l; 315 uid_t uid; 316 u_int rtableid; 317 318 if ((rcvsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) 319 err(5, "icmp socket"); 320 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 321 err(5, "raw socket"); 322 323 /* revoke privs */ 324 uid = getuid(); 325 if (setresuid(uid, uid, uid) == -1) 326 err(1, "setresuid"); 327 328 (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &max_ttl, &size, 329 NULL, 0); 330 331 while ((ch = getopt(argc, argv, "AcDdf:g:Ilm:nP:p:q:Ss:t:V:vw:x")) 332 != -1) 333 switch (ch) { 334 case 'A': 335 Aflag++; 336 break; 337 case 'c': 338 incflag = 0; 339 break; 340 case 'd': 341 options |= SO_DEBUG; 342 break; 343 case 'D': 344 dump = 1; 345 break; 346 case 'f': 347 errno = 0; 348 ep = NULL; 349 l = strtol(optarg, &ep, 10); 350 if (errno || !*optarg || *ep || l < 1 || l > max_ttl) 351 errx(1, "min ttl must be 1 to %u.", max_ttl); 352 first_ttl = (u_int8_t)l; 353 break; 354 case 'g': 355 if (lsrr >= MAX_LSRR) 356 errx(1, "too many gateways; max %d", MAX_LSRR); 357 if (inet_aton(optarg, &gateway[lsrr]) == 0) { 358 hp = gethostbyname(optarg); 359 if (hp == 0) 360 errx(1, "unknown host %s", optarg); 361 memcpy(&gateway[lsrr], hp->h_addr, hp->h_length); 362 } 363 if (++lsrr == 1) 364 lsrrlen = 4; 365 lsrrlen += 4; 366 break; 367 case 'I': 368 if (protoset) 369 errx(1, "protocol already set with -P"); 370 protoset = 1; 371 proto = IPPROTO_ICMP; 372 break; 373 case 'l': 374 ttl_flag++; 375 break; 376 case 'm': 377 errno = 0; 378 ep = NULL; 379 l = strtol(optarg, &ep, 10); 380 if (errno || !*optarg || *ep || l < first_ttl || 381 l > MAXTTL) 382 errx(1, "max ttl must be %u to %u.", first_ttl, 383 MAXTTL); 384 max_ttl = (u_int8_t)l; 385 break; 386 case 'n': 387 nflag++; 388 break; 389 case 'p': 390 errno = 0; 391 ep = NULL; 392 l = strtol(optarg, &ep, 10); 393 if (errno || !*optarg || *ep || l <= 0 || l >= 65536) 394 errx(1, "port must be >0, <65536."); 395 port = (u_int16_t)l; 396 break; 397 case 'P': 398 if (protoset) 399 errx(1, "protocol already set with -I"); 400 protoset = 1; 401 errno = 0; 402 ep = NULL; 403 l = strtol(optarg, &ep, 10); 404 if (errno || !*optarg || *ep || l < 1 || 405 l >= IPPROTO_MAX) { 406 struct protoent *pent; 407 408 pent = getprotobyname(optarg); 409 if (pent) 410 proto = pent->p_proto; 411 else 412 errx(1, "proto must be >=1, or a name."); 413 } else 414 proto = (int)l; 415 break; 416 case 'q': 417 errno = 0; 418 ep = NULL; 419 l = strtol(optarg, &ep, 10); 420 if (errno || !*optarg || *ep || l < 1 || l > INT_MAX) 421 errx(1, "nprobes must be >0."); 422 nprobes = (int)l; 423 break; 424 case 's': 425 /* 426 * set the ip source address of the outbound 427 * probe (e.g., on a multi-homed host). 428 */ 429 source = optarg; 430 break; 431 case 'S': 432 sump = 1; 433 break; 434 case 't': 435 if (!map_tos(optarg, &tos)) { 436 errno = 0; 437 errstr = NULL; 438 if (strlen(optarg) > 1 && optarg[0] == '0' && 439 optarg[1] == 'x') 440 tos = (int)strtol(optarg, NULL, 16); 441 else 442 tos = (int)strtonum(optarg, 0, 255, 443 &errstr); 444 if (tos < 0 || tos > 255 || errstr || errno) 445 errx(1, "illegal tos value %s", 446 optarg); 447 } 448 tflag = 1; 449 last_tos = tos; 450 break; 451 case 'v': 452 verbose++; 453 break; 454 case 'V': 455 rtableid = (unsigned int)strtonum(optarg, 0, 456 RT_TABLEID_MAX, &errstr); 457 if (errstr) 458 errx(1, "rtable value is %s: %s", 459 errstr, optarg); 460 if (setsockopt(sndsock, SOL_SOCKET, SO_RTABLE, 461 &rtableid, sizeof(rtableid)) == -1) 462 err(1, "setsockopt SO_RTABLE"); 463 if (setsockopt(rcvsock, SOL_SOCKET, SO_RTABLE, 464 &rtableid, sizeof(rtableid)) == -1) 465 err(1, "setsockopt SO_RTABLE"); 466 break; 467 case 'w': 468 errno = 0; 469 ep = NULL; 470 l = strtol(optarg, &ep, 10); 471 if (errno || !*optarg || *ep || l <= 1 || l > INT_MAX) 472 errx(1, "wait must be >1 sec."); 473 waittime = (int)l; 474 break; 475 case 'x': 476 xflag = 1; 477 break; 478 default: 479 usage(); 480 } 481 argc -= optind; 482 argv += optind; 483 484 if (argc < 1 || argc > 2) 485 usage(); 486 487 setvbuf(stdout, NULL, _IOLBF, 0); 488 489 (void) memset(&to, 0, sizeof(struct sockaddr)); 490 to.sin_family = AF_INET; 491 if (inet_aton(*argv, &to.sin_addr) != 0) 492 hostname = *argv; 493 else { 494 hp = gethostbyname(*argv); 495 if (hp == 0) 496 errx(1, "unknown host %s", *argv); 497 to.sin_family = hp->h_addrtype; 498 memcpy(&to.sin_addr, hp->h_addr, hp->h_length); 499 if ((hostname = strdup(hp->h_name)) == NULL) 500 err(1, "malloc"); 501 if (hp->h_addr_list[1] != NULL) 502 warnx("Warning: %s has multiple addresses; using %s", 503 hostname, inet_ntoa(to.sin_addr)); 504 } 505 if (*++argv) { 506 errno = 0; 507 ep = NULL; 508 l = strtol(*argv, &ep, 10); 509 if (errno || !*argv || *ep || l < 0 || l > INT_MAX) 510 errx(1, "datalen out of range"); 511 datalen = (int)l; 512 } 513 514 switch (proto) { 515 case IPPROTO_UDP: 516 headerlen = (sizeof(struct ip) + lsrrlen + 517 sizeof(struct udphdr) + sizeof(struct packetdata)); 518 break; 519 case IPPROTO_ICMP: 520 headerlen = (sizeof(struct ip) + lsrrlen + 521 sizeof(struct icmp) + sizeof(struct packetdata)); 522 break; 523 default: 524 headerlen = (sizeof(struct ip) + lsrrlen + 525 sizeof(struct packetdata)); 526 } 527 528 if (datalen < 0 || datalen > IP_MAXPACKET - headerlen) 529 errx(1, "packet size must be 0 to %d.", 530 IP_MAXPACKET - headerlen); 531 532 datalen += headerlen; 533 534 if ((outpacket = calloc(1, datalen)) == NULL) 535 err(1, "calloc"); 536 537 ip = (struct ip *)outpacket; 538 if (lsrr != 0) { 539 u_char *p = (u_char *)(ip + 1); 540 541 *p++ = IPOPT_NOP; 542 *p++ = IPOPT_LSRR; 543 *p++ = lsrrlen - 1; 544 *p++ = IPOPT_MINOFF; 545 gateway[lsrr] = to.sin_addr; 546 for (i = 1; i <= lsrr; i++) { 547 memcpy(p, &gateway[i], sizeof(struct in_addr)); 548 p += sizeof(struct in_addr); 549 } 550 ip->ip_dst = gateway[0]; 551 } else 552 ip->ip_dst = to.sin_addr; 553 ip->ip_off = htons(0); 554 ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2; 555 ip->ip_p = proto; 556 ip->ip_v = IPVERSION; 557 ip->ip_tos = tos; 558 559 ident = (getpid() & 0xffff) | 0x8000; 560 tmprnd = arc4random(); 561 sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) : 562 (tmprnd & 0x7ff); 563 usec_perturb = arc4random(); 564 565 if (options & SO_DEBUG) 566 (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 567 (char *)&on, sizeof(on)); 568 #ifdef SO_SNDBUF 569 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 570 sizeof(datalen)) < 0) 571 err(6, "SO_SNDBUF"); 572 #endif /* SO_SNDBUF */ 573 #ifdef IP_HDRINCL 574 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 575 sizeof(on)) < 0) 576 err(6, "IP_HDRINCL"); 577 #endif /* IP_HDRINCL */ 578 if (options & SO_DEBUG) 579 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 580 (char *)&on, sizeof(on)); 581 582 if (source) { 583 (void) memset(&from, 0, sizeof(struct sockaddr)); 584 from.sin_family = AF_INET; 585 if (inet_aton(source, &from.sin_addr) == 0) 586 errx(1, "unknown host %s", source); 587 ip->ip_src = from.sin_addr; 588 if (getuid() != 0 && 589 (ntohl(from.sin_addr.s_addr) & 0xff000000U) == 0x7f000000U && 590 (ntohl(to.sin_addr.s_addr) & 0xff000000U) != 0x7f000000U) 591 errx(1, "source is on 127/8, destination is not"); 592 593 if (getuid() && 594 bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) 595 err(1, "bind"); 596 } 597 598 fprintf(stderr, "traceroute to %s (%s)", hostname, 599 inet_ntoa(to.sin_addr)); 600 if (source) 601 fprintf(stderr, " from %s", source); 602 fprintf(stderr, ", %u hops max, %d byte packets\n", max_ttl, datalen); 603 (void) fflush(stderr); 604 605 if (first_ttl > 1) 606 printf("Skipping %u intermediate hops\n", first_ttl - 1); 607 608 for (ttl = first_ttl; ttl && ttl <= max_ttl; ++ttl) { 609 int got_there = 0, unreachable = 0, timeout = 0, loss; 610 in_addr_t lastaddr = 0; 611 quad_t dt; 612 613 printf("%2u ", ttl); 614 for (probe = 0, loss = 0; probe < nprobes; ++probe) { 615 int cc; 616 struct timeval t1, t2; 617 int code; 618 619 (void) gettimeofday(&t1, NULL); 620 send_probe(++seq, ttl, incflag, &to); 621 while ((cc = wait_for_reply(rcvsock, &from, &t1))) { 622 (void) gettimeofday(&t2, NULL); 623 if (t2.tv_sec - t1.tv_sec > waittime) { 624 cc = 0; 625 break; 626 } 627 i = packet_ok(packet, cc, &from, seq, incflag); 628 /* Skip short packet */ 629 if (i == 0) 630 continue; 631 if (from.sin_addr.s_addr != lastaddr) { 632 print((struct sockaddr *)&from, 633 (cc - (((struct ip*)packet)->ip_hl 634 <<2)), inet_ntop(AF_INET, 635 &((struct ip*)packet)->ip_dst, 636 hbuf, sizeof(hbuf))); 637 lastaddr = from.sin_addr.s_addr; 638 } 639 dt = (quad_t)(t2.tv_sec - t1.tv_sec) * 1000000 + 640 (quad_t)(t2.tv_usec - t1.tv_usec); 641 printf(" %u", (u_int)(dt / 1000)); 642 if (dt % 1000) 643 printf(".%u", (u_int)(dt % 1000)); 644 printf(" ms"); 645 ip = (struct ip *)packet; 646 if (ttl_flag) 647 printf(" (%u)", ip->ip_ttl); 648 if (i == -2) { 649 #ifndef ARCHAIC 650 ip = (struct ip *)packet; 651 if (ip->ip_ttl <= 1) 652 printf(" !"); 653 #endif 654 ++got_there; 655 break; 656 } 657 658 icp = (struct icmp *) (((u_char *)ip)+(ip->ip_hl<<2)); 659 inner_ip = (struct ip *) (((u_char *)icp)+8); 660 661 tos_returned = inner_ip->ip_tos; 662 663 if (tflag && (tos_returned != last_tos)) 664 printf (" (TOS=%d!)", tos_returned); 665 666 last_tos = tos_returned; 667 668 /* time exceeded in transit */ 669 if (i == -1) 670 break; 671 code = i - 1; 672 switch (code) { 673 case ICMP_UNREACH_PORT: 674 #ifndef ARCHAIC 675 ip = (struct ip *)packet; 676 if (ip->ip_ttl <= 1) 677 printf(" !"); 678 #endif /* ARCHAIC */ 679 ++got_there; 680 break; 681 case ICMP_UNREACH_NET: 682 ++unreachable; 683 printf(" !N"); 684 break; 685 case ICMP_UNREACH_HOST: 686 ++unreachable; 687 printf(" !H"); 688 break; 689 case ICMP_UNREACH_PROTOCOL: 690 ++got_there; 691 printf(" !P"); 692 break; 693 case ICMP_UNREACH_NEEDFRAG: 694 ++unreachable; 695 printf(" !F"); 696 break; 697 case ICMP_UNREACH_SRCFAIL: 698 ++unreachable; 699 printf(" !S"); 700 break; 701 case ICMP_UNREACH_FILTER_PROHIB: 702 ++unreachable; 703 printf(" !X"); 704 break; 705 case ICMP_UNREACH_NET_PROHIB: /*misuse*/ 706 ++unreachable; 707 printf(" !A"); 708 break; 709 case ICMP_UNREACH_HOST_PROHIB: 710 ++unreachable; 711 printf(" !C"); 712 break; 713 case ICMP_UNREACH_NET_UNKNOWN: 714 case ICMP_UNREACH_HOST_UNKNOWN: 715 ++unreachable; 716 printf(" !U"); 717 break; 718 case ICMP_UNREACH_ISOLATED: 719 ++unreachable; 720 printf(" !I"); 721 break; 722 case ICMP_UNREACH_TOSNET: 723 case ICMP_UNREACH_TOSHOST: 724 ++unreachable; 725 printf(" !T"); 726 break; 727 default: 728 ++unreachable; 729 printf(" !<%d>", i - 1); 730 break; 731 } 732 break; 733 } 734 if (cc == 0) { 735 printf(" *"); 736 timeout++; 737 loss++; 738 } else if (cc && probe == nprobes - 1 && 739 (xflag || verbose)) 740 print_exthdr(packet, cc); 741 (void) fflush(stdout); 742 } 743 if (sump) 744 printf(" (%d%% loss)", (loss * 100) / nprobes); 745 putchar('\n'); 746 if (got_there || 747 (unreachable && (unreachable + timeout) >= nprobes)) 748 break; 749 } 750 exit(0); 751 } 752 753 void 754 print_exthdr(u_char *buf, int cc) 755 { 756 struct icmp_ext_hdr exthdr; 757 struct icmp_ext_obj_hdr objhdr; 758 struct ip *ip; 759 struct icmp *icp; 760 int hlen, first; 761 u_int32_t label; 762 u_int16_t off, olen; 763 u_int8_t type; 764 765 ip = (struct ip *)buf; 766 hlen = ip->ip_hl << 2; 767 if (cc < hlen + ICMP_MINLEN) 768 return; 769 icp = (struct icmp *)(buf + hlen); 770 cc -= hlen + ICMP_MINLEN; 771 buf += hlen + ICMP_MINLEN; 772 773 type = icp->icmp_type; 774 if (type != ICMP_TIMXCEED && type != ICMP_UNREACH && 775 type != ICMP_PARAMPROB) 776 /* Wrong ICMP type for extension */ 777 return; 778 779 off = icp->icmp_length * sizeof(u_int32_t); 780 if (off == 0) 781 /* 782 * rfc 4884 Section 5.5: traceroute MUST try to parse 783 * broken ext headers. Again IETF bent over to please 784 * idotic corporations. 785 */ 786 off = ICMP_EXT_OFFSET; 787 else if (off < ICMP_EXT_OFFSET) 788 /* rfc 4884 requires an offset of at least 128 bytes */ 789 return; 790 791 /* make sure that at least one extension is present */ 792 if (cc < off + sizeof(exthdr) + sizeof(objhdr)) 793 /* Not enough space for ICMP extensions */ 794 return; 795 796 cc -= off; 797 buf += off; 798 memcpy(&exthdr, buf, sizeof(exthdr)); 799 800 /* verify version */ 801 if ((exthdr.ieh_version & ICMP_EXT_HDR_VMASK) != ICMP_EXT_HDR_VERSION) 802 return; 803 804 /* verify checksum */ 805 if (exthdr.ieh_cksum && in_cksum((u_short *)buf, cc)) 806 return; 807 808 buf += sizeof(exthdr); 809 cc -= sizeof(exthdr); 810 811 while (cc > sizeof(objhdr)) { 812 memcpy(&objhdr, buf, sizeof(objhdr)); 813 olen = ntohs(objhdr.ieo_length); 814 815 /* Sanity check the length field */ 816 if (olen < sizeof(objhdr) || olen > cc) 817 return; 818 819 cc -= olen; 820 821 /* Move past the object header */ 822 buf += sizeof(objhdr); 823 olen -= sizeof(objhdr); 824 825 switch (objhdr.ieo_cnum) { 826 case ICMP_EXT_MPLS: 827 /* RFC 4950: ICMP Extensions for MPLS */ 828 switch (objhdr.ieo_ctype) { 829 case 1: 830 first = 0; 831 while (olen >= sizeof(u_int32_t)) { 832 memcpy(&label, buf, sizeof(u_int32_t)); 833 label = htonl(label); 834 buf += sizeof(u_int32_t); 835 olen -= sizeof(u_int32_t); 836 837 if (first == 0) { 838 printf(" [MPLS Label "); 839 first++; 840 } else 841 printf(", "); 842 printf("%d", MPLS_LABEL(label)); 843 if (MPLS_EXP(label)) 844 printf(" (Exp %x)", 845 MPLS_EXP(label)); 846 } 847 if (olen > 0) { 848 printf("|]"); 849 return; 850 } 851 if (first != 0) 852 printf("]"); 853 break; 854 default: 855 buf += olen; 856 break; 857 } 858 break; 859 case ICMP_EXT_IFINFO: 860 default: 861 buf += olen; 862 break; 863 } 864 } 865 } 866 867 int 868 wait_for_reply(int sock, struct sockaddr_in *from, struct timeval *sent) 869 { 870 socklen_t fromlen = sizeof (*from); 871 struct timeval now, wait; 872 int cc = 0, fdsn; 873 fd_set *fdsp; 874 875 fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask); 876 if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 877 err(1, "malloc"); 878 memset(fdsp, 0, fdsn); 879 FD_SET(sock, fdsp); 880 gettimeofday(&now, NULL); 881 wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec; 882 wait.tv_usec = sent->tv_usec - now.tv_usec; 883 if (wait.tv_usec < 0) { 884 wait.tv_usec += 1000000; 885 wait.tv_sec--; 886 } 887 if (wait.tv_sec < 0) 888 timerclear(&wait); 889 890 if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) 891 cc = recvfrom(rcvsock, (char *)packet, sizeof(packet), 0, 892 (struct sockaddr *)from, &fromlen); 893 894 free(fdsp); 895 return (cc); 896 } 897 898 void 899 dump_packet(void) 900 { 901 u_char *p; 902 int i; 903 904 fprintf(stderr, "packet data:"); 905 for (p = outpacket, i = 0; i < datalen; i++) { 906 if ((i % 24) == 0) 907 fprintf(stderr, "\n "); 908 fprintf(stderr, " %02x", *p++); 909 } 910 fprintf(stderr, "\n"); 911 } 912 913 void 914 send_probe(int seq, u_int8_t ttl, int iflag, struct sockaddr_in *to) 915 { 916 struct ip *ip = (struct ip *)outpacket; 917 u_char *p = (u_char *)(ip + 1); 918 struct udphdr *up = (struct udphdr *)(p + lsrrlen); 919 struct icmp *icmpp = (struct icmp *)(p + lsrrlen); 920 struct packetdata *op; 921 struct timeval tv; 922 int i; 923 924 ip->ip_len = htons(datalen); 925 ip->ip_ttl = ttl; 926 ip->ip_id = htons(ident+seq); 927 928 switch (proto) { 929 case IPPROTO_ICMP: 930 icmpp->icmp_type = icmp_type; 931 icmpp->icmp_code = icmp_code; 932 icmpp->icmp_seq = htons(seq); 933 icmpp->icmp_id = htons(ident); 934 op = (struct packetdata *)(icmpp + 1); 935 break; 936 case IPPROTO_UDP: 937 up->uh_sport = htons(ident); 938 if (iflag) 939 up->uh_dport = htons(port+seq); 940 else 941 up->uh_dport = htons(port); 942 up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) - 943 lsrrlen)); 944 up->uh_sum = 0; 945 op = (struct packetdata *)(up + 1); 946 break; 947 default: 948 op = (struct packetdata *)(ip + 1); 949 break; 950 } 951 op->seq = seq; 952 op->ttl = ttl; 953 (void) gettimeofday(&tv, NULL); 954 955 /* 956 * We don't want hostiles snooping the net to get any useful 957 * information about us. Send the timestamp in network byte order, 958 * and perturb the timestamp enough that they won't know our 959 * real clock ticker. We don't want to perturb the time by too 960 * much: being off by a suspiciously large amount might indicate 961 * OpenBSD. 962 * 963 * The timestamps in the packet are currently unused. If future 964 * work wants to use them they will have to subtract out the 965 * perturbation first. 966 */ 967 (void) gettimeofday(&tv, NULL); 968 op->sec = htonl(tv.tv_sec + sec_perturb); 969 op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000); 970 971 if (proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) { 972 icmpp->icmp_cksum = 0; 973 icmpp->icmp_cksum = in_cksum((u_short *)icmpp, 974 datalen - sizeof(struct ip) - lsrrlen); 975 if (icmpp->icmp_cksum == 0) 976 icmpp->icmp_cksum = 0xffff; 977 } 978 979 if (dump) 980 dump_packet(); 981 982 i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to, 983 sizeof(struct sockaddr_in)); 984 if (i < 0 || i != datalen) { 985 if (i < 0) 986 perror("sendto"); 987 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, 988 datalen, i); 989 (void) fflush(stdout); 990 } 991 } 992 993 static char *ttab[] = { 994 "Echo Reply", 995 "ICMP 1", 996 "ICMP 2", 997 "Dest Unreachable", 998 "Source Quench", 999 "Redirect", 1000 "ICMP 6", 1001 "ICMP 7", 1002 "Echo", 1003 "Router Advert", 1004 "Router Solicit", 1005 "Time Exceeded", 1006 "Param Problem", 1007 "Timestamp", 1008 "Timestamp Reply", 1009 "Info Request", 1010 "Info Reply", 1011 "Mask Request", 1012 "Mask Reply" 1013 }; 1014 1015 /* 1016 * Convert an ICMP "type" field to a printable string. 1017 */ 1018 char * 1019 pr_type(u_int8_t t) 1020 { 1021 if (t > 18) 1022 return ("OUT-OF-RANGE"); 1023 return (ttab[t]); 1024 } 1025 1026 int 1027 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq, int iflag) 1028 { 1029 struct icmp *icp; 1030 u_char code; 1031 u_int8_t type; 1032 int hlen; 1033 #ifndef ARCHAIC 1034 struct ip *ip; 1035 1036 ip = (struct ip *) buf; 1037 hlen = ip->ip_hl << 2; 1038 if (cc < hlen + ICMP_MINLEN) { 1039 if (verbose) 1040 printf("packet too short (%d bytes) from %s\n", cc, 1041 inet_ntoa(from->sin_addr)); 1042 return (0); 1043 } 1044 cc -= hlen; 1045 icp = (struct icmp *)(buf + hlen); 1046 #else 1047 icp = (struct icmp *)buf; 1048 #endif /* ARCHAIC */ 1049 type = icp->icmp_type; 1050 code = icp->icmp_code; 1051 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 1052 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { 1053 struct ip *hip; 1054 struct udphdr *up; 1055 struct icmp *icmpp; 1056 1057 hip = &icp->icmp_ip; 1058 hlen = hip->ip_hl << 2; 1059 1060 switch (proto) { 1061 case IPPROTO_ICMP: 1062 if (icmp_type == ICMP_ECHO && 1063 type == ICMP_ECHOREPLY && 1064 icp->icmp_id == htons(ident) && 1065 icp->icmp_seq == htons(seq)) 1066 return (-2); /* we got there */ 1067 1068 icmpp = (struct icmp *)((u_char *)hip + hlen); 1069 if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP && 1070 icmpp->icmp_id == htons(ident) && 1071 icmpp->icmp_seq == htons(seq)) 1072 return (type == ICMP_TIMXCEED? -1 : code + 1); 1073 break; 1074 1075 case IPPROTO_UDP: 1076 up = (struct udphdr *)((u_char *)hip + hlen); 1077 if (hlen + 12 <= cc && hip->ip_p == proto && 1078 up->uh_sport == htons(ident) && 1079 ((iflag && up->uh_dport == htons(port + seq)) || 1080 (!iflag && up->uh_dport == htons(port)))) 1081 return (type == ICMP_TIMXCEED? -1 : code + 1); 1082 break; 1083 default: 1084 /* this is some odd, user specified proto, 1085 * how do we check it? 1086 */ 1087 if (hip->ip_p == proto) 1088 return (type == ICMP_TIMXCEED? -1 : code + 1); 1089 } 1090 } 1091 #ifndef ARCHAIC 1092 if (verbose) { 1093 int i; 1094 in_addr_t *lp = (in_addr_t *)&icp->icmp_ip; 1095 1096 printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr)); 1097 printf(" to %s", inet_ntoa(ip->ip_dst)); 1098 printf(": icmp type %u (%s) code %d\n", type, pr_type(type), 1099 icp->icmp_code); 1100 for (i = 4; i < cc ; i += sizeof(in_addr_t)) 1101 printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++); 1102 } 1103 #endif /* ARCHAIC */ 1104 return (0); 1105 } 1106 1107 void 1108 print(struct sockaddr *from, int cc, const char *to) 1109 { 1110 char hbuf[NI_MAXHOST]; 1111 if (getnameinfo(from, from->sa_len, 1112 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1113 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1114 if (nflag) 1115 printf(" %s", hbuf); 1116 else 1117 printf(" %s (%s)", inetname(from), hbuf); 1118 1119 if (Aflag) 1120 print_asn((struct sockaddr_storage *)from); 1121 1122 if (verbose) 1123 printf(" %d bytes to %s", cc, to); 1124 } 1125 1126 /* 1127 * Checksum routine for Internet Protocol family headers (C Version) 1128 */ 1129 u_short 1130 in_cksum(u_short *addr, int len) 1131 { 1132 u_short *w = addr, answer; 1133 int nleft = len, sum = 0; 1134 1135 /* 1136 * Our algorithm is simple, using a 32 bit accumulator (sum), 1137 * we add sequential 16 bit words to it, and at the end, fold 1138 * back all the carry bits from the top 16 bits into the lower 1139 * 16 bits. 1140 */ 1141 while (nleft > 1) { 1142 sum += *w++; 1143 nleft -= 2; 1144 } 1145 1146 /* mop up an odd byte, if necessary */ 1147 if (nleft == 1) 1148 sum += *(u_char *)w; 1149 1150 /* 1151 * add back carry outs from top 16 bits to low 16 bits 1152 */ 1153 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 1154 sum += (sum >> 16); /* add carry */ 1155 answer = ~sum; /* truncate to 16 bits */ 1156 return (answer); 1157 } 1158 1159 /* 1160 * Construct an Internet address representation. 1161 */ 1162 const char * 1163 inetname(struct sockaddr *sa) 1164 { 1165 static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1]; 1166 static int first = 1; 1167 char *cp; 1168 1169 if (first) { 1170 first = 0; 1171 if (gethostname(domain, sizeof(domain)) == 0 && 1172 (cp = strchr(domain, '.')) != NULL) 1173 (void) strlcpy(domain, cp + 1, sizeof(domain)); 1174 else 1175 domain[0] = 0; 1176 } 1177 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1178 NI_NAMEREQD) == 0) { 1179 if ((cp = strchr(line, '.')) != NULL && strcmp(cp + 1, 1180 domain) == 0) 1181 *cp = '\0'; 1182 return (line); 1183 } 1184 1185 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1186 NI_NUMERICHOST) != 0) 1187 return ("invalid"); 1188 return (line); 1189 } 1190 1191 void 1192 print_asn(struct sockaddr_storage *ss) 1193 { 1194 struct rrsetinfo *answers = NULL; 1195 int counter; 1196 const u_char *uaddr; 1197 char qbuf[MAXDNAME], *qp; 1198 1199 switch (ss->ss_family) { 1200 case AF_INET: 1201 uaddr = (const u_char *)&((struct sockaddr_in *) ss)->sin_addr; 1202 if (snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u." 1203 "origin.asn.cymru.com", 1204 (uaddr[3] & 0xff), (uaddr[2] & 0xff), 1205 (uaddr[1] & 0xff), (uaddr[0] & 0xff)) >= sizeof (qbuf)) 1206 return; 1207 break; 1208 case AF_INET6: 1209 uaddr = (const u_char *)&((struct sockaddr_in6 *) ss)->sin6_addr; 1210 if (snprintf(qbuf, sizeof qbuf, 1211 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 1212 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 1213 "origin6.asn.cymru.com", 1214 (uaddr[15] & 0x0f), ((uaddr[15] >>4)& 0x0f), 1215 (uaddr[14] & 0x0f), ((uaddr[14] >>4)& 0x0f), 1216 (uaddr[13] & 0x0f), ((uaddr[13] >>4)& 0x0f), 1217 (uaddr[12] & 0x0f), ((uaddr[12] >>4)& 0x0f), 1218 (uaddr[11] & 0x0f), ((uaddr[11] >>4)& 0x0f), 1219 (uaddr[10] & 0x0f), ((uaddr[10] >>4)& 0x0f), 1220 (uaddr[9] & 0x0f), ((uaddr[9] >>4)& 0x0f), 1221 (uaddr[8] & 0x0f), ((uaddr[8] >>4)& 0x0f), 1222 (uaddr[7] & 0x0f), ((uaddr[7] >>4)& 0x0f), 1223 (uaddr[6] & 0x0f), ((uaddr[6] >>4)& 0x0f), 1224 (uaddr[5] & 0x0f), ((uaddr[5] >>4)& 0x0f), 1225 (uaddr[4] & 0x0f), ((uaddr[4] >>4)& 0x0f), 1226 (uaddr[3] & 0x0f), ((uaddr[3] >>4)& 0x0f), 1227 (uaddr[2] & 0x0f), ((uaddr[2] >>4)& 0x0f), 1228 (uaddr[1] & 0x0f), ((uaddr[1] >>4)& 0x0f), 1229 (uaddr[0] & 0x0f), ((uaddr[0] >>4)& 0x0f)) >= sizeof (qbuf)) 1230 return; 1231 break; 1232 default: 1233 return; 1234 } 1235 1236 if (getrrsetbyname(qbuf, C_IN, T_TXT, 0, &answers) != 0) 1237 return; 1238 for (counter = 0; counter < answers->rri_nrdatas; counter++) { 1239 char *p, *as = answers->rri_rdatas[counter].rdi_data; 1240 as++; /* skip first byte, it contains length */ 1241 if ((p = strchr(as,'|'))) { 1242 printf(counter ? ", " : " ["); 1243 p[-1] = 0; 1244 printf("AS%s", as); 1245 } 1246 } 1247 if (counter) 1248 printf("]"); 1249 1250 freerrset(answers); 1251 } 1252 1253 int 1254 map_tos(char *s, int *val) 1255 { 1256 /* DiffServ Codepoints and other TOS mappings */ 1257 const struct toskeywords { 1258 const char *keyword; 1259 int val; 1260 } *t, toskeywords[] = { 1261 { "af11", IPTOS_DSCP_AF11 }, 1262 { "af12", IPTOS_DSCP_AF12 }, 1263 { "af13", IPTOS_DSCP_AF13 }, 1264 { "af21", IPTOS_DSCP_AF21 }, 1265 { "af22", IPTOS_DSCP_AF22 }, 1266 { "af23", IPTOS_DSCP_AF23 }, 1267 { "af31", IPTOS_DSCP_AF31 }, 1268 { "af32", IPTOS_DSCP_AF32 }, 1269 { "af33", IPTOS_DSCP_AF33 }, 1270 { "af41", IPTOS_DSCP_AF41 }, 1271 { "af42", IPTOS_DSCP_AF42 }, 1272 { "af43", IPTOS_DSCP_AF43 }, 1273 { "critical", IPTOS_PREC_CRITIC_ECP }, 1274 { "cs0", IPTOS_DSCP_CS0 }, 1275 { "cs1", IPTOS_DSCP_CS1 }, 1276 { "cs2", IPTOS_DSCP_CS2 }, 1277 { "cs3", IPTOS_DSCP_CS3 }, 1278 { "cs4", IPTOS_DSCP_CS4 }, 1279 { "cs5", IPTOS_DSCP_CS5 }, 1280 { "cs6", IPTOS_DSCP_CS6 }, 1281 { "cs7", IPTOS_DSCP_CS7 }, 1282 { "ef", IPTOS_DSCP_EF }, 1283 { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 1284 { "lowdelay", IPTOS_LOWDELAY }, 1285 { "netcontrol", IPTOS_PREC_NETCONTROL }, 1286 { "reliability", IPTOS_RELIABILITY }, 1287 { "throughput", IPTOS_THROUGHPUT }, 1288 { NULL, -1 }, 1289 }; 1290 1291 for (t = toskeywords; t->keyword != NULL; t++) { 1292 if (strcmp(s, t->keyword) == 0) { 1293 *val = t->val; 1294 return (1); 1295 } 1296 } 1297 1298 return (0); 1299 } 1300 1301 void 1302 usage(void) 1303 { 1304 extern char *__progname; 1305 1306 fprintf(stderr, 1307 "usage: %s [-AcDdIlnSvx] [-f first_ttl] [-g gateway_addr] [-m max_ttl]\n" 1308 "\t[-P proto] [-p port] [-q nqueries] [-s src_addr] [-t toskeyword]\n" 1309 "\t[-V rtable] [-w waittime] host [packetsize]\n", __progname); 1310 exit(1); 1311 } 1312