1 /* $OpenBSD: traceroute.c,v 1.132 2014/06/05 14:49:11 florian Exp $ */ 2 /* $NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1990, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * Van Jacobson. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /* 66 * traceroute host - trace the route ip packets follow going to "host". 67 * 68 * Attempt to trace the route an ip packet would follow to some 69 * internet host. We find out intermediate hops by launching probe 70 * packets with a small ttl (time to live) then listening for an 71 * icmp "time exceeded" reply from a gateway. We start our probes 72 * with a ttl of one and increase by one until we get an icmp "port 73 * unreachable" (which means we got to "host") or hit a max (which 74 * defaults to 64 hops & can be changed with the -m flag). Three 75 * probes (change with -q flag) are sent at each ttl setting and a 76 * line is printed showing the ttl, address of the gateway and 77 * round trip time of each probe. If the probe answers come from 78 * different gateways, the address of each responding system will 79 * be printed. If there is no response within a 5 sec. timeout 80 * interval (changed with the -w flag), a "*" is printed for that 81 * probe. 82 * 83 * Probe packets are UDP format. We don't want the destination 84 * host to process them so the destination port is set to an 85 * unlikely value (if some clod on the destination is using that 86 * value, it can be changed with the -p flag). 87 * 88 * A sample use might be: 89 * 90 * [yak 71]% traceroute nis.nsf.net. 91 * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet 92 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 93 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 94 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 95 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 96 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 97 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 98 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 99 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 100 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 101 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 102 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 103 * 104 * Note that lines 2 & 3 are the same. This is due to a buggy 105 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 106 * packets with a zero ttl. 107 * 108 * A more interesting example is: 109 * 110 * [yak 72]% traceroute allspice.lcs.mit.edu. 111 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max 112 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 113 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 114 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 115 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 116 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 117 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 118 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 119 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 120 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 121 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 122 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 123 * 12 * * * 124 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 125 * 14 * * * 126 * 15 * * * 127 * 16 * * * 128 * 17 * * * 129 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 130 * 131 * (I start to see why I'm having so much trouble with mail to 132 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 133 * either don't send ICMP "time exceeded" messages or send them 134 * with a ttl too small to reach us. 14 - 17 are running the 135 * MIT C Gateway code that doesn't send "time exceeded"s. God 136 * only knows what's going on with 12. 137 * 138 * The silent gateway 12 in the above may be the result of a bug in 139 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 140 * sends an unreachable message using whatever ttl remains in the 141 * original datagram. Since, for gateways, the remaining ttl is 142 * zero, the icmp "time exceeded" is guaranteed to not make it back 143 * to us. The behavior of this bug is slightly more interesting 144 * when it appears on the destination system: 145 * 146 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 147 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 148 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 149 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 150 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 151 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 152 * 7 * * * 153 * 8 * * * 154 * 9 * * * 155 * 10 * * * 156 * 11 * * * 157 * 12 * * * 158 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 159 * 160 * Notice that there are 12 "gateways" (13 is the final 161 * destination) and exactly the last half of them are "missing". 162 * What's really happening is that rip (a Sun-3 running Sun OS3.5) 163 * is using the ttl from our arriving datagram as the ttl in its 164 * icmp reply. So, the reply will time out on the return path 165 * (with no notice sent to anyone since icmp's aren't sent for 166 * icmp's) until we probe with a ttl that's at least twice the path 167 * length. I.e., rip is really only 7 hops away. A reply that 168 * returns with a ttl of 1 is a clue this problem exists. 169 * Traceroute prints a "!" after the time if the ttl is <= 1. 170 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 171 * non-standard (HPUX) software, expect to see this problem 172 * frequently and/or take care picking the target host of your 173 * probes. 174 * 175 * Other possible annotations after the time are !H, !N, !P (got a host, 176 * network or protocol unreachable, respectively), !S or !F (source 177 * route failed or fragmentation needed -- neither of these should 178 * ever occur and the associated gateway is busted if you see one). If 179 * almost all the probes result in some kind of unreachable, traceroute 180 * will give up and exit. 181 * 182 * Notes 183 * ----- 184 * This program must be run by root or be setuid. (I suggest that 185 * you *don't* make it setuid -- casual use could result in a lot 186 * of unnecessary traffic on our poor, congested nets.) 187 * 188 * This program requires a kernel mod that does not appear in any 189 * system available from Berkeley: A raw ip socket using proto 190 * IPPROTO_RAW must interpret the data sent as an ip datagram (as 191 * opposed to data to be wrapped in a ip datagram). See the README 192 * file that came with the source to this program for a description 193 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 194 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 195 * MODIFIED TO RUN THIS PROGRAM. 196 * 197 * The udp port usage may appear bizarre (well, ok, it is bizarre). 198 * The problem is that an icmp message only contains 8 bytes of 199 * data from the original datagram. 8 bytes is the size of a udp 200 * header so, if we want to associate replies with the original 201 * datagram, the necessary information must be encoded into the 202 * udp header (the ip id could be used but there's no way to 203 * interlock with the kernel's assignment of ip id's and, anyway, 204 * it would have taken a lot more kernel hacking to allow this 205 * code to set the ip id). So, to allow two or more users to 206 * use traceroute simultaneously, we use this task's pid as the 207 * source port (the high bit is set to move the port number out 208 * of the "likely" range). To keep track of which probe is being 209 * replied to (so times and/or hop counts don't get confused by a 210 * reply that was delayed in transit), we increment the destination 211 * port number before each probe. 212 * 213 * Don't use this as a coding example. I was trying to find a 214 * routing problem and this code sort-of popped out after 48 hours 215 * without sleep. I was amazed it ever compiled, much less ran. 216 * 217 * I stole the idea for this program from Steve Deering. Since 218 * the first release, I've learned that had I attended the right 219 * IETF working group meetings, I also could have stolen it from Guy 220 * Almes or Matt Mathis. I don't know (or care) who came up with 221 * the idea first. I envy the originators' perspicacity and I'm 222 * glad they didn't keep the idea a secret. 223 * 224 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 225 * enhancements to the original distribution. 226 * 227 * I've hacked up a round-trip-route version of this that works by 228 * sending a loose-source-routed udp datagram through the destination 229 * back to yourself. Unfortunately, SO many gateways botch source 230 * routing, the thing is almost worthless. Maybe one day... 231 * 232 * -- Van Jacobson (van@helios.ee.lbl.gov) 233 * Tue Dec 20 03:50:13 PST 1988 234 */ 235 236 #include <sys/param.h> 237 #include <sys/time.h> 238 #include <sys/socket.h> 239 #include <sys/uio.h> 240 #include <sys/file.h> 241 #include <sys/ioctl.h> 242 #include <sys/sysctl.h> 243 244 #include <netinet/in_systm.h> 245 #include <netinet/in.h> 246 #include <netinet/ip.h> 247 #include <netinet/ip_icmp.h> 248 #include <netinet/ip_var.h> 249 #include <netinet/ip6.h> 250 #include <netinet/icmp6.h> 251 #include <netinet/udp.h> 252 253 #define DUMMY_PORT 10010 254 255 #include <arpa/inet.h> 256 #include <arpa/nameser.h> 257 258 #include <netmpls/mpls.h> 259 260 #include <ctype.h> 261 #include <err.h> 262 #include <poll.h> 263 #include <errno.h> 264 #include <netdb.h> 265 #include <stdio.h> 266 #include <stdlib.h> 267 #include <string.h> 268 #include <unistd.h> 269 270 #define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4) 271 272 #define MPLS_LABEL(m) ((m & MPLS_LABEL_MASK) >> MPLS_LABEL_OFFSET) 273 #define MPLS_EXP(m) ((m & MPLS_EXP_MASK) >> MPLS_EXP_OFFSET) 274 275 /* 276 * Format of the data in a (udp) probe packet. 277 */ 278 struct packetdata { 279 u_char seq; /* sequence number of this packet */ 280 u_int8_t ttl; /* ttl packet left with */ 281 u_char pad[2]; 282 u_int32_t sec; /* time packet left */ 283 u_int32_t usec; 284 } __packed; 285 286 struct in_addr gateway[MAX_LSRR + 1]; 287 int lsrrlen = 0; 288 int32_t sec_perturb; 289 int32_t usec_perturb; 290 291 u_char packet[512], *outpacket; /* last inbound (icmp) packet */ 292 293 int wait_for_reply(int, struct msghdr *); 294 void dump_packet(void); 295 void build_probe4(int, u_int8_t, int); 296 void build_probe6(int, u_int8_t, int, struct sockaddr *); 297 void send_probe(int, u_int8_t, int, struct sockaddr *); 298 struct udphdr *get_udphdr(struct ip6_hdr *, u_char *); 299 int packet_ok(int, struct msghdr *, int, int, int); 300 int packet_ok4(struct msghdr *, int, int, int); 301 int packet_ok6(struct msghdr *, int, int, int); 302 void icmp_code(int, int, int *, int *); 303 void icmp4_code(int, int *, int *); 304 void icmp6_code(int, int *, int *); 305 void dump_packet(void); 306 void print_exthdr(u_char *, int); 307 void check_tos(struct ip*); 308 void print(struct sockaddr *, int, const char *); 309 const char *inetname(struct sockaddr*); 310 void print_asn(struct sockaddr_storage *); 311 u_short in_cksum(u_short *, int); 312 char *pr_type(u_int8_t); 313 int map_tos(char *, int *); 314 double deltaT(struct timeval *, struct timeval *); 315 void usage(void); 316 317 int rcvsock; /* receive (icmp) socket file descriptor */ 318 int sndsock; /* send (udp) socket file descriptor */ 319 320 struct msghdr rcvmhdr; 321 struct iovec rcviov[2]; 322 323 int rcvhlim; 324 struct in6_pktinfo *rcvpktinfo; 325 326 int datalen; /* How much data */ 327 int headerlen; /* How long packet's header is */ 328 329 char *source = 0; 330 char *hostname; 331 332 int nprobes = 3; 333 u_int8_t max_ttl = IPDEFTTL; 334 u_int8_t first_ttl = 1; 335 u_short ident; 336 u_int16_t srcport; 337 u_int16_t port = 32768+666; /* start udp dest port # for probe packets */ 338 u_char proto = IPPROTO_UDP; 339 u_int8_t icmp_type = ICMP_ECHO; /* default ICMP code/type */ 340 #define ICMP_CODE 0; 341 int options; /* socket options */ 342 int verbose; 343 int waittime = 5; /* time to wait for response (in seconds) */ 344 int nflag; /* print addresses numerically */ 345 int dump; 346 int xflag; /* show ICMP extension header */ 347 int tflag; /* tos flag was set */ 348 int Aflag; /* lookup ASN */ 349 int last_tos; 350 int v6flag; 351 352 extern char *__progname; 353 354 int 355 main(int argc, char *argv[]) 356 { 357 int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; 358 int ttl_flag = 0, incflag = 1, protoset = 0, sump = 0; 359 int ch, i, lsrr = 0, on = 1, probe, seq = 0, tos = 0, error, packetlen; 360 int rcvcmsglen, rcvsock4, rcvsock6, sndsock4, sndsock6; 361 int v4sock_errno, v6sock_errno; 362 struct addrinfo hints, *res; 363 size_t size; 364 static u_char *rcvcmsgbuf; 365 struct sockaddr_in from4, to4; 366 struct sockaddr_in6 from6, to6; 367 struct sockaddr *from, *to; 368 struct hostent *hp; 369 u_int32_t tmprnd; 370 struct ip *ip = NULL; 371 u_int8_t ttl; 372 char *ep, hbuf[NI_MAXHOST], *dest; 373 const char *errstr; 374 long l; 375 uid_t uid; 376 u_int rtableid; 377 socklen_t len; 378 379 rcvsock4 = rcvsock6 = sndsock4 = sndsock6 = -1; 380 v4sock_errno = v6sock_errno = 0; 381 382 if ((rcvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) 383 v6sock_errno = errno; 384 else if ((sndsock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 385 v6sock_errno = errno; 386 387 if ((rcvsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) 388 v4sock_errno = errno; 389 else if ((sndsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 390 v4sock_errno = errno; 391 392 /* revoke privs */ 393 uid = getuid(); 394 if (setresuid(uid, uid, uid) == -1) 395 err(1, "setresuid"); 396 397 if (strcmp("traceroute6", __progname) == 0) { 398 v6flag = 1; 399 if (v6sock_errno != 0) 400 errc(5, v6sock_errno, rcvsock6 < 0 ? "socket(ICMPv6)" : 401 "socket(SOCK_DGRAM)"); 402 rcvsock = rcvsock6; 403 sndsock = sndsock6; 404 if (rcvsock4 >= 0) 405 close(rcvsock4); 406 if (sndsock4 >= 0) 407 close(sndsock4); 408 } else { 409 if (v4sock_errno != 0) 410 errc(5, v4sock_errno, rcvsock4 < 0 ? "icmp socket" : 411 "raw socket"); 412 rcvsock = rcvsock4; 413 sndsock = sndsock4; 414 if (rcvsock6 >= 0) 415 close(rcvsock6); 416 if (sndsock6 >= 0) 417 close(sndsock6); 418 } 419 420 if (v6flag) { 421 mib[1] = PF_INET6; 422 mib[2] = IPPROTO_IPV6; 423 mib[3] = IPV6CTL_DEFHLIM; 424 /* specify to tell receiving interface */ 425 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 426 sizeof(on)) < 0) 427 err(1, "setsockopt(IPV6_RECVPKTINFO)"); 428 429 /* specify to tell hoplimit field of received IP6 hdr */ 430 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 431 sizeof(on)) < 0) 432 err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 433 } 434 435 size = sizeof(i); 436 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0) == -1) 437 err(1, "sysctl"); 438 max_ttl = i; 439 440 while ((ch = getopt(argc, argv, v6flag ? "AcDdf:Ilm:np:q:Ss:w:vV:" : 441 "AcDdf:g:Ilm:nP:p:q:Ss:t:V:vw:x")) != -1) 442 switch (ch) { 443 case 'A': 444 Aflag++; 445 break; 446 case 'c': 447 incflag = 0; 448 break; 449 case 'd': 450 options |= SO_DEBUG; 451 break; 452 case 'D': 453 dump = 1; 454 break; 455 case 'f': 456 errno = 0; 457 ep = NULL; 458 l = strtol(optarg, &ep, 10); 459 if (errno || !*optarg || *ep || l < 1 || l > max_ttl) 460 errx(1, "min ttl must be 1 to %u.", max_ttl); 461 first_ttl = (u_int8_t)l; 462 break; 463 case 'g': 464 if (lsrr >= MAX_LSRR) 465 errx(1, "too many gateways; max %d", MAX_LSRR); 466 if (inet_aton(optarg, &gateway[lsrr]) == 0) { 467 hp = gethostbyname(optarg); 468 if (hp == 0) 469 errx(1, "unknown host %s", optarg); 470 memcpy(&gateway[lsrr], hp->h_addr, 471 hp->h_length); 472 } 473 if (++lsrr == 1) 474 lsrrlen = 4; 475 lsrrlen += 4; 476 break; 477 case 'I': 478 if (protoset) 479 errx(1, "protocol already set with -P"); 480 protoset = 1; 481 proto = IPPROTO_ICMP; 482 break; 483 case 'l': 484 ttl_flag++; 485 break; 486 case 'm': 487 errno = 0; 488 ep = NULL; 489 l = strtol(optarg, &ep, 10); 490 if (errno || !*optarg || *ep || l < first_ttl || 491 l > MAXTTL) 492 errx(1, "max ttl must be %u to %u.", first_ttl, 493 MAXTTL); 494 max_ttl = (u_int8_t)l; 495 break; 496 case 'n': 497 nflag++; 498 break; 499 case 'p': 500 errno = 0; 501 ep = NULL; 502 l = strtol(optarg, &ep, 10); 503 if (errno || !*optarg || *ep || l <= 0 || l >= 65536) 504 errx(1, "port must be >0, <65536."); 505 port = (u_int16_t)l; 506 break; 507 case 'P': 508 if (protoset) 509 errx(1, "protocol already set with -I"); 510 protoset = 1; 511 errno = 0; 512 ep = NULL; 513 l = strtol(optarg, &ep, 10); 514 if (errno || !*optarg || *ep || l < 1 || 515 l >= IPPROTO_MAX) { 516 struct protoent *pent; 517 518 pent = getprotobyname(optarg); 519 if (pent) 520 proto = pent->p_proto; 521 else 522 errx(1, "proto must be >=1, or a " 523 "name."); 524 } else 525 proto = (int)l; 526 break; 527 case 'q': 528 errno = 0; 529 ep = NULL; 530 l = strtol(optarg, &ep, 10); 531 if (errno || !*optarg || *ep || l < 1 || l > INT_MAX) 532 errx(1, "nprobes must be >0."); 533 nprobes = (int)l; 534 break; 535 case 's': 536 /* 537 * set the ip source address of the outbound 538 * probe (e.g., on a multi-homed host). 539 */ 540 source = optarg; 541 break; 542 case 'S': 543 sump = 1; 544 break; 545 case 't': 546 if (!map_tos(optarg, &tos)) { 547 errno = 0; 548 errstr = NULL; 549 if (strlen(optarg) > 1 && optarg[0] == '0' && 550 optarg[1] == 'x') 551 tos = (int)strtol(optarg, NULL, 16); 552 else 553 tos = (int)strtonum(optarg, 0, 255, 554 &errstr); 555 if (tos < 0 || tos > 255 || errstr || errno) 556 errx(1, "illegal tos value %s", 557 optarg); 558 } 559 tflag = 1; 560 last_tos = tos; 561 break; 562 case 'v': 563 verbose++; 564 break; 565 case 'V': 566 rtableid = (unsigned int)strtonum(optarg, 0, 567 RT_TABLEID_MAX, &errstr); 568 if (errstr) 569 errx(1, "rtable value is %s: %s", 570 errstr, optarg); 571 if (setsockopt(sndsock, SOL_SOCKET, SO_RTABLE, 572 &rtableid, sizeof(rtableid)) == -1) 573 err(1, "setsockopt SO_RTABLE"); 574 if (setsockopt(rcvsock, SOL_SOCKET, SO_RTABLE, 575 &rtableid, sizeof(rtableid)) == -1) 576 err(1, "setsockopt SO_RTABLE"); 577 break; 578 case 'w': 579 errno = 0; 580 ep = NULL; 581 l = strtol(optarg, &ep, 10); 582 if (errno || !*optarg || *ep || l <= 1 || l > INT_MAX) 583 errx(1, "wait must be >1 sec."); 584 waittime = (int)l; 585 break; 586 case 'x': 587 xflag = 1; 588 break; 589 default: 590 usage(); 591 } 592 argc -= optind; 593 argv += optind; 594 595 if (argc < 1 || argc > 2) 596 usage(); 597 598 setvbuf(stdout, NULL, _IOLBF, 0); 599 600 ident = (getpid() & 0xffff) | 0x8000; 601 tmprnd = arc4random(); 602 sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) : 603 (tmprnd & 0x7ff); 604 usec_perturb = arc4random(); 605 606 (void) memset(&to4, 0, sizeof(to4)); 607 (void) memset(&to6, 0, sizeof(to6)); 608 609 if (inet_aton(*argv, &to4.sin_addr) != 0) { 610 hostname = *argv; 611 if ((dest = strdup(inet_ntoa(to4.sin_addr))) == NULL) 612 errx(1, "malloc"); 613 } else 614 dest = *argv; 615 616 memset(&hints, 0, sizeof(hints)); 617 hints.ai_family = v6flag ? PF_INET6 : PF_INET; 618 hints.ai_socktype = SOCK_RAW; 619 hints.ai_protocol = 0; 620 hints.ai_flags = AI_CANONNAME; 621 if ((error = getaddrinfo(dest, NULL, &hints, &res))) 622 errx(1, "%s", gai_strerror(error)); 623 624 switch (res->ai_family) { 625 case AF_INET: 626 if (res->ai_addrlen != sizeof(to4)) 627 errx(1, "size of sockaddr mismatch"); 628 629 to = (struct sockaddr *)&to4; 630 from = (struct sockaddr *)&from4; 631 break; 632 case AF_INET6: 633 if (res->ai_addrlen != sizeof(to6)) 634 errx(1, "size of sockaddr mismatch"); 635 636 to = (struct sockaddr *)&to6; 637 from = (struct sockaddr *)&from6; 638 break; 639 default: 640 errx(1, "unsupported AF: %d", res->ai_family); 641 break; 642 } 643 644 memcpy(to, res->ai_addr, res->ai_addrlen); 645 646 if (!hostname) { 647 hostname = res->ai_canonname ? strdup(res->ai_canonname) : dest; 648 if (!hostname) 649 errx(1, "malloc"); 650 } 651 652 if (res->ai_next) { 653 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, 654 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 655 strlcpy(hbuf, "?", sizeof(hbuf)); 656 warnx("Warning: %s has multiple " 657 "addresses; using %s\n", hostname, hbuf); 658 } 659 freeaddrinfo(res); 660 661 if (*++argv) { 662 errno = 0; 663 ep = NULL; 664 l = strtol(*argv, &ep, 10); 665 if (errno || !*argv || *ep || l < 0 || l > INT_MAX) 666 errx(1, "datalen out of range"); 667 datalen = (int)l; 668 } 669 670 switch (to->sa_family) { 671 case AF_INET: 672 switch (proto) { 673 case IPPROTO_UDP: 674 headerlen = (sizeof(struct ip) + lsrrlen + 675 sizeof(struct udphdr) + sizeof(struct packetdata)); 676 break; 677 case IPPROTO_ICMP: 678 headerlen = (sizeof(struct ip) + lsrrlen + 679 sizeof(struct icmp) + sizeof(struct packetdata)); 680 break; 681 default: 682 headerlen = (sizeof(struct ip) + lsrrlen + 683 sizeof(struct packetdata)); 684 } 685 686 if (datalen < 0 || datalen > IP_MAXPACKET - headerlen) 687 errx(1, "packet size must be 0 to %d.", 688 IP_MAXPACKET - headerlen); 689 690 datalen += headerlen; 691 692 if ((outpacket = calloc(1, datalen)) == NULL) 693 err(1, "calloc"); 694 695 rcviov[0].iov_base = (caddr_t)packet; 696 rcviov[0].iov_len = sizeof(packet); 697 rcvmhdr.msg_name = (caddr_t)&from4; 698 rcvmhdr.msg_namelen = sizeof(from4); 699 rcvmhdr.msg_iov = rcviov; 700 rcvmhdr.msg_iovlen = 1; 701 rcvmhdr.msg_control = NULL; 702 rcvmhdr.msg_controllen = 0; 703 704 ip = (struct ip *)outpacket; 705 if (lsrr != 0) { 706 u_char *p = (u_char *)(ip + 1); 707 708 *p++ = IPOPT_NOP; 709 *p++ = IPOPT_LSRR; 710 *p++ = lsrrlen - 1; 711 *p++ = IPOPT_MINOFF; 712 gateway[lsrr] = to4.sin_addr; 713 for (i = 1; i <= lsrr; i++) { 714 memcpy(p, &gateway[i], sizeof(struct in_addr)); 715 p += sizeof(struct in_addr); 716 } 717 ip->ip_dst = gateway[0]; 718 } else 719 ip->ip_dst = to4.sin_addr; 720 ip->ip_off = htons(0); 721 ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2; 722 ip->ip_p = proto; 723 ip->ip_v = IPVERSION; 724 ip->ip_tos = tos; 725 726 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 727 sizeof(on)) < 0) 728 err(6, "IP_HDRINCL"); 729 730 if (source) { 731 (void) memset(&from4, 0, sizeof(from4)); 732 from4.sin_family = AF_INET; 733 if (inet_aton(source, &from4.sin_addr) == 0) 734 errx(1, "unknown host %s", source); 735 ip->ip_src = from4.sin_addr; 736 if (getuid() != 0 && 737 (ntohl(from4.sin_addr.s_addr) & 0xff000000U) == 738 0x7f000000U && (ntohl(to4.sin_addr.s_addr) & 739 0xff000000U) != 0x7f000000U) 740 errx(1, "source is on 127/8, destination is" 741 " not"); 742 if (getuid() && bind(sndsock, (struct sockaddr *)&from4, 743 sizeof(from4)) < 0) 744 err(1, "bind"); 745 } 746 packetlen = datalen; 747 break; 748 case AF_INET6: 749 /* 750 * packetlen is the size of the complete IP packet sent and 751 * reported in the first line of output. 752 * For IPv4 this is equal to datalen since we are constructing 753 * a raw packet. 754 * For IPv6 we need to always add the size of the IP6 header 755 * and for UDP packets the size of the UDP header since they 756 * are prepended to the packet by the kernel 757 */ 758 packetlen = sizeof(struct ip6_hdr); 759 switch (proto) { 760 case IPPROTO_UDP: 761 headerlen = sizeof(struct packetdata); 762 packetlen += sizeof(struct udphdr); 763 break; 764 case IPPROTO_ICMP: 765 headerlen = sizeof(struct icmp6_hdr) + 766 sizeof(struct packetdata); 767 break; 768 default: 769 errx(1, "Unsupported proto: %hhu", proto); 770 break; 771 } 772 773 if (datalen < 0 || datalen > IP_MAXPACKET - headerlen) 774 errx(1, "packet size must be 0 to %d.", 775 IP_MAXPACKET - headerlen); 776 777 datalen += headerlen; 778 packetlen += datalen; 779 780 if ((outpacket = calloc(1, datalen)) == NULL) 781 err(1, "calloc"); 782 783 /* initialize msghdr for receiving packets */ 784 rcviov[0].iov_base = (caddr_t)packet; 785 rcviov[0].iov_len = sizeof(packet); 786 rcvmhdr.msg_name = (caddr_t)&from6; 787 rcvmhdr.msg_namelen = sizeof(from6); 788 rcvmhdr.msg_iov = rcviov; 789 rcvmhdr.msg_iovlen = 1; 790 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 791 CMSG_SPACE(sizeof(int)); 792 793 if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) 794 errx(1, "malloc"); 795 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 796 rcvmhdr.msg_controllen = rcvcmsglen; 797 798 /* 799 * Send UDP or ICMP 800 */ 801 if (proto == IPPROTO_ICMP) { 802 close(sndsock); 803 sndsock = rcvsock; 804 } 805 806 /* 807 * Source selection 808 */ 809 memset(&from6, 0, sizeof(from6)); 810 if (source) { 811 memset(&hints, 0, sizeof(hints)); 812 hints.ai_family = AF_INET6; 813 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 814 hints.ai_flags = AI_NUMERICHOST; 815 if ((error = getaddrinfo(source, "0", &hints, &res))) 816 errx(1, "%s: %s", source, gai_strerror(error)); 817 if (res->ai_addrlen != sizeof(from6)) 818 errx(1, "size of sockaddr mismatch"); 819 memcpy(&from6, res->ai_addr, res->ai_addrlen); 820 freeaddrinfo(res); 821 } else { 822 struct sockaddr_in6 nxt; 823 int dummy; 824 825 nxt = to6; 826 nxt.sin6_port = htons(DUMMY_PORT); 827 if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 828 err(1, "socket"); 829 if (connect(dummy, (struct sockaddr *)&nxt, 830 nxt.sin6_len) < 0) 831 err(1, "connect"); 832 len = sizeof(from6); 833 if (getsockname(dummy, (struct sockaddr *)&from6, 834 &len) < 0) 835 err(1, "getsockname"); 836 close(dummy); 837 } 838 839 from6.sin6_port = htons(0); 840 if (bind(sndsock, (struct sockaddr *)&from6, from6.sin6_len) < 841 0) 842 err(1, "bind sndsock"); 843 844 len = sizeof(from6); 845 if (getsockname(sndsock, (struct sockaddr *)&from6, &len) < 0) 846 err(1, "getsockname"); 847 srcport = ntohs(from6.sin6_port); 848 break; 849 default: 850 errx(1, "unsupported AF: %d", to->sa_family); 851 break; 852 } 853 854 if (options & SO_DEBUG) { 855 (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 856 (char *)&on, sizeof(on)); 857 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 858 (char *)&on, sizeof(on)); 859 } 860 861 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 862 sizeof(datalen)) < 0) 863 err(6, "SO_SNDBUF"); 864 865 if (getnameinfo(to, to->sa_len, hbuf, 866 sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) 867 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 868 fprintf(stderr, "%s to %s (%s)", __progname, hostname, hbuf); 869 if (source) 870 fprintf(stderr, " from %s", source); 871 fprintf(stderr, ", %u hops max, %d byte packets\n", max_ttl, packetlen); 872 (void) fflush(stderr); 873 874 if (first_ttl > 1) 875 printf("Skipping %u intermediate hops\n", first_ttl - 1); 876 877 for (ttl = first_ttl; ttl && ttl <= max_ttl; ++ttl) { 878 int got_there = 0, unreachable = 0, timeout = 0, loss; 879 in_addr_t lastaddr = 0; 880 struct in6_addr lastaddr6; 881 882 printf("%2u ", ttl); 883 memset(&lastaddr6, 0, sizeof(lastaddr6)); 884 for (probe = 0, loss = 0; probe < nprobes; ++probe) { 885 int cc; 886 struct timeval t1, t2; 887 888 (void) gettimeofday(&t1, NULL); 889 send_probe(++seq, ttl, incflag, to); 890 while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 891 (void) gettimeofday(&t2, NULL); 892 i = packet_ok(to->sa_family, &rcvmhdr, cc, seq, 893 incflag); 894 /* Skip short packet */ 895 if (i == 0) 896 continue; 897 if (to->sa_family == AF_INET) { 898 ip = (struct ip *)packet; 899 if (from4.sin_addr.s_addr != lastaddr) { 900 print(from, 901 cc - (ip->ip_hl << 2), 902 inet_ntop(AF_INET, 903 &ip->ip_dst, hbuf, 904 sizeof(hbuf))); 905 lastaddr = 906 from4.sin_addr.s_addr; 907 } 908 } else if (to->sa_family == AF_INET6) { 909 if (!IN6_ARE_ADDR_EQUAL( 910 &from6.sin6_addr, &lastaddr6)) { 911 print(from, cc, rcvpktinfo ? 912 inet_ntop( AF_INET6, 913 &rcvpktinfo->ipi6_addr, 914 hbuf, sizeof(hbuf)) : "?"); 915 lastaddr6 = from6.sin6_addr; 916 } 917 } else 918 errx(1, "unsupported AF: %d", 919 to->sa_family); 920 921 printf(" %g ms", deltaT(&t1, &t2)); 922 if (ttl_flag) 923 printf(" (%u)", v6flag ? rcvhlim : 924 ip->ip_ttl); 925 if (to->sa_family == AF_INET) { 926 if (i == -2) { 927 if (ip->ip_ttl <= 1) 928 printf(" !"); 929 ++got_there; 930 break; 931 } 932 933 if (tflag) 934 check_tos(ip); 935 } 936 937 /* time exceeded in transit */ 938 if (i == -1) 939 break; 940 icmp_code(to->sa_family, i - 1, &got_there, 941 &unreachable); 942 break; 943 } 944 if (cc == 0) { 945 printf(" *"); 946 timeout++; 947 loss++; 948 } else if (cc && probe == nprobes - 1 && 949 (xflag || verbose)) 950 print_exthdr(packet, cc); 951 (void) fflush(stdout); 952 } 953 if (sump) 954 printf(" (%d%% loss)", (loss * 100) / nprobes); 955 putchar('\n'); 956 if (got_there || 957 (unreachable && (unreachable + timeout) >= nprobes)) 958 break; 959 } 960 exit(0); 961 } 962 963 void 964 print_exthdr(u_char *buf, int cc) 965 { 966 struct icmp_ext_hdr exthdr; 967 struct icmp_ext_obj_hdr objhdr; 968 struct ip *ip; 969 struct icmp *icp; 970 int hlen, first; 971 u_int32_t label; 972 u_int16_t off, olen; 973 u_int8_t type; 974 975 ip = (struct ip *)buf; 976 hlen = ip->ip_hl << 2; 977 if (cc < hlen + ICMP_MINLEN) 978 return; 979 icp = (struct icmp *)(buf + hlen); 980 cc -= hlen + ICMP_MINLEN; 981 buf += hlen + ICMP_MINLEN; 982 983 type = icp->icmp_type; 984 if (type != ICMP_TIMXCEED && type != ICMP_UNREACH && 985 type != ICMP_PARAMPROB) 986 /* Wrong ICMP type for extension */ 987 return; 988 989 off = icp->icmp_length * sizeof(u_int32_t); 990 if (off == 0) 991 /* 992 * rfc 4884 Section 5.5: traceroute MUST try to parse 993 * broken ext headers. Again IETF bent over to please 994 * idotic corporations. 995 */ 996 off = ICMP_EXT_OFFSET; 997 else if (off < ICMP_EXT_OFFSET) 998 /* rfc 4884 requires an offset of at least 128 bytes */ 999 return; 1000 1001 /* make sure that at least one extension is present */ 1002 if (cc < off + sizeof(exthdr) + sizeof(objhdr)) 1003 /* Not enough space for ICMP extensions */ 1004 return; 1005 1006 cc -= off; 1007 buf += off; 1008 memcpy(&exthdr, buf, sizeof(exthdr)); 1009 1010 /* verify version */ 1011 if ((exthdr.ieh_version & ICMP_EXT_HDR_VMASK) != ICMP_EXT_HDR_VERSION) 1012 return; 1013 1014 /* verify checksum */ 1015 if (exthdr.ieh_cksum && in_cksum((u_short *)buf, cc)) 1016 return; 1017 1018 buf += sizeof(exthdr); 1019 cc -= sizeof(exthdr); 1020 1021 while (cc > sizeof(objhdr)) { 1022 memcpy(&objhdr, buf, sizeof(objhdr)); 1023 olen = ntohs(objhdr.ieo_length); 1024 1025 /* Sanity check the length field */ 1026 if (olen < sizeof(objhdr) || olen > cc) 1027 return; 1028 1029 cc -= olen; 1030 1031 /* Move past the object header */ 1032 buf += sizeof(objhdr); 1033 olen -= sizeof(objhdr); 1034 1035 switch (objhdr.ieo_cnum) { 1036 case ICMP_EXT_MPLS: 1037 /* RFC 4950: ICMP Extensions for MPLS */ 1038 switch (objhdr.ieo_ctype) { 1039 case 1: 1040 first = 0; 1041 while (olen >= sizeof(u_int32_t)) { 1042 memcpy(&label, buf, sizeof(u_int32_t)); 1043 label = htonl(label); 1044 buf += sizeof(u_int32_t); 1045 olen -= sizeof(u_int32_t); 1046 1047 if (first == 0) { 1048 printf(" [MPLS Label "); 1049 first++; 1050 } else 1051 printf(", "); 1052 printf("%d", MPLS_LABEL(label)); 1053 if (MPLS_EXP(label)) 1054 printf(" (Exp %x)", 1055 MPLS_EXP(label)); 1056 } 1057 if (olen > 0) { 1058 printf("|]"); 1059 return; 1060 } 1061 if (first != 0) 1062 printf("]"); 1063 break; 1064 default: 1065 buf += olen; 1066 break; 1067 } 1068 break; 1069 case ICMP_EXT_IFINFO: 1070 default: 1071 buf += olen; 1072 break; 1073 } 1074 } 1075 } 1076 1077 void 1078 check_tos(struct ip *ip) 1079 { 1080 struct icmp *icp; 1081 struct ip *inner_ip; 1082 1083 icp = (struct icmp *) (((u_char *)ip)+(ip->ip_hl<<2)); 1084 inner_ip = (struct ip *) (((u_char *)icp)+8); 1085 1086 if (inner_ip->ip_tos != last_tos) 1087 printf (" (TOS=%d!)", inner_ip->ip_tos); 1088 1089 last_tos = inner_ip->ip_tos; 1090 } 1091 1092 int 1093 wait_for_reply(int sock, struct msghdr *mhdr) 1094 { 1095 struct pollfd pfd[1]; 1096 int cc = 0; 1097 1098 pfd[0].fd = sock; 1099 pfd[0].events = POLLIN; 1100 pfd[0].revents = 0; 1101 1102 if (poll(pfd, 1, waittime * 1000) > 0) 1103 cc = recvmsg(rcvsock, mhdr, 0); 1104 1105 return (cc); 1106 } 1107 1108 void 1109 dump_packet(void) 1110 { 1111 u_char *p; 1112 int i; 1113 1114 fprintf(stderr, "packet data:"); 1115 for (p = outpacket, i = 0; i < datalen; i++) { 1116 if ((i % 24) == 0) 1117 fprintf(stderr, "\n "); 1118 fprintf(stderr, " %02x", *p++); 1119 } 1120 fprintf(stderr, "\n"); 1121 } 1122 1123 void 1124 build_probe4(int seq, u_int8_t ttl, int iflag) 1125 { 1126 struct ip *ip = (struct ip *)outpacket; 1127 u_char *p = (u_char *)(ip + 1); 1128 struct udphdr *up = (struct udphdr *)(p + lsrrlen); 1129 struct icmp *icmpp = (struct icmp *)(p + lsrrlen); 1130 struct packetdata *op; 1131 struct timeval tv; 1132 1133 ip->ip_len = htons(datalen); 1134 ip->ip_ttl = ttl; 1135 ip->ip_id = htons(ident+seq); 1136 1137 switch (proto) { 1138 case IPPROTO_ICMP: 1139 icmpp->icmp_type = icmp_type; 1140 icmpp->icmp_code = ICMP_CODE; 1141 icmpp->icmp_seq = htons(seq); 1142 icmpp->icmp_id = htons(ident); 1143 op = (struct packetdata *)(icmpp + 1); 1144 break; 1145 case IPPROTO_UDP: 1146 up->uh_sport = htons(ident); 1147 if (iflag) 1148 up->uh_dport = htons(port+seq); 1149 else 1150 up->uh_dport = htons(port); 1151 up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) - 1152 lsrrlen)); 1153 up->uh_sum = 0; 1154 op = (struct packetdata *)(up + 1); 1155 break; 1156 default: 1157 op = (struct packetdata *)(ip + 1); 1158 break; 1159 } 1160 op->seq = seq; 1161 op->ttl = ttl; 1162 (void) gettimeofday(&tv, NULL); 1163 1164 /* 1165 * We don't want hostiles snooping the net to get any useful 1166 * information about us. Send the timestamp in network byte order, 1167 * and perturb the timestamp enough that they won't know our 1168 * real clock ticker. We don't want to perturb the time by too 1169 * much: being off by a suspiciously large amount might indicate 1170 * OpenBSD. 1171 * 1172 * The timestamps in the packet are currently unused. If future 1173 * work wants to use them they will have to subtract out the 1174 * perturbation first. 1175 */ 1176 (void) gettimeofday(&tv, NULL); 1177 op->sec = htonl(tv.tv_sec + sec_perturb); 1178 op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000); 1179 1180 if (proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) { 1181 icmpp->icmp_cksum = 0; 1182 icmpp->icmp_cksum = in_cksum((u_short *)icmpp, 1183 datalen - sizeof(struct ip) - lsrrlen); 1184 if (icmpp->icmp_cksum == 0) 1185 icmpp->icmp_cksum = 0xffff; 1186 } 1187 } 1188 1189 void 1190 build_probe6(int seq, u_int8_t hops, int iflag, struct sockaddr *to) 1191 { 1192 struct timeval tv; 1193 struct packetdata *op; 1194 int i; 1195 1196 i = hops; 1197 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 1198 (char *)&i, sizeof(i)) < 0) 1199 warn("setsockopt IPV6_UNICAST_HOPS"); 1200 1201 if (iflag) 1202 ((struct sockaddr_in6*)to)->sin6_port = htons(port + seq); 1203 else 1204 ((struct sockaddr_in6*)to)->sin6_port = htons(port); 1205 (void) gettimeofday(&tv, NULL); 1206 1207 if (proto == IPPROTO_ICMP) { 1208 struct icmp6_hdr *icp = (struct icmp6_hdr *)outpacket; 1209 1210 icp->icmp6_type = ICMP6_ECHO_REQUEST; 1211 icp->icmp6_code = 0; 1212 icp->icmp6_cksum = 0; 1213 icp->icmp6_id = ident; 1214 icp->icmp6_seq = htons(seq); 1215 op = (struct packetdata *)(outpacket + 1216 sizeof(struct icmp6_hdr)); 1217 } else 1218 op = (struct packetdata *)outpacket; 1219 op->seq = seq; 1220 op->ttl = hops; 1221 op->sec = htonl(tv.tv_sec); 1222 op->usec = htonl(tv.tv_usec); 1223 } 1224 1225 void 1226 send_probe(int seq, u_int8_t ttl, int iflag, struct sockaddr *to) 1227 { 1228 int i; 1229 1230 switch (to->sa_family) { 1231 case AF_INET: 1232 build_probe4(seq, ttl, iflag); 1233 break; 1234 case AF_INET6: 1235 build_probe6(seq, ttl, iflag, to); 1236 break; 1237 default: 1238 errx(1, "unsupported AF: %d", to->sa_family); 1239 break; 1240 } 1241 1242 if (dump) 1243 dump_packet(); 1244 1245 i = sendto(sndsock, outpacket, datalen, 0, to, to->sa_len); 1246 if (i < 0 || i != datalen) { 1247 if (i < 0) 1248 warn("sendto"); 1249 printf("%s: wrote %s %d chars, ret=%d\n", __progname, hostname, 1250 datalen, i); 1251 (void) fflush(stdout); 1252 } 1253 } 1254 1255 double 1256 deltaT(struct timeval *t1p, struct timeval *t2p) 1257 { 1258 double dt; 1259 1260 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 1261 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 1262 return (dt); 1263 } 1264 1265 static char *ttab[] = { 1266 "Echo Reply", 1267 "ICMP 1", 1268 "ICMP 2", 1269 "Dest Unreachable", 1270 "Source Quench", 1271 "Redirect", 1272 "ICMP 6", 1273 "ICMP 7", 1274 "Echo", 1275 "Router Advert", 1276 "Router Solicit", 1277 "Time Exceeded", 1278 "Param Problem", 1279 "Timestamp", 1280 "Timestamp Reply", 1281 "Info Request", 1282 "Info Reply", 1283 "Mask Request", 1284 "Mask Reply" 1285 }; 1286 1287 /* 1288 * Convert an ICMP "type" field to a printable string. 1289 */ 1290 char * 1291 pr_type(u_int8_t t) 1292 { 1293 if (t > 18) 1294 return ("OUT-OF-RANGE"); 1295 return (ttab[t]); 1296 } 1297 1298 int 1299 packet_ok(int af, struct msghdr *mhdr, int cc, int seq, int iflag) 1300 { 1301 switch (af) { 1302 case AF_INET: 1303 return packet_ok4(mhdr, cc, seq, iflag); 1304 break; 1305 case AF_INET6: 1306 return packet_ok6(mhdr, cc, seq, iflag); 1307 break; 1308 default: 1309 errx(1, "unsupported AF: %d", af); 1310 break; 1311 } 1312 } 1313 1314 int 1315 packet_ok4(struct msghdr *mhdr, int cc,int seq, int iflag) 1316 { 1317 struct sockaddr_in *from = (struct sockaddr_in *)mhdr->msg_name; 1318 struct icmp *icp; 1319 u_char code; 1320 char *buf = (char *)mhdr->msg_iov[0].iov_base; 1321 u_int8_t type; 1322 int hlen; 1323 struct ip *ip; 1324 1325 ip = (struct ip *) buf; 1326 hlen = ip->ip_hl << 2; 1327 if (cc < hlen + ICMP_MINLEN) { 1328 if (verbose) 1329 printf("packet too short (%d bytes) from %s\n", cc, 1330 inet_ntoa(from->sin_addr)); 1331 return (0); 1332 } 1333 cc -= hlen; 1334 icp = (struct icmp *)(buf + hlen); 1335 type = icp->icmp_type; 1336 code = icp->icmp_code; 1337 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 1338 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { 1339 struct ip *hip; 1340 struct udphdr *up; 1341 struct icmp *icmpp; 1342 1343 hip = &icp->icmp_ip; 1344 hlen = hip->ip_hl << 2; 1345 1346 switch (proto) { 1347 case IPPROTO_ICMP: 1348 if (icmp_type == ICMP_ECHO && 1349 type == ICMP_ECHOREPLY && 1350 icp->icmp_id == htons(ident) && 1351 icp->icmp_seq == htons(seq)) 1352 return (-2); /* we got there */ 1353 1354 icmpp = (struct icmp *)((u_char *)hip + hlen); 1355 if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP && 1356 icmpp->icmp_id == htons(ident) && 1357 icmpp->icmp_seq == htons(seq)) 1358 return (type == ICMP_TIMXCEED? -1 : code + 1); 1359 break; 1360 1361 case IPPROTO_UDP: 1362 up = (struct udphdr *)((u_char *)hip + hlen); 1363 if (hlen + 12 <= cc && hip->ip_p == proto && 1364 up->uh_sport == htons(ident) && 1365 ((iflag && up->uh_dport == htons(port + seq)) || 1366 (!iflag && up->uh_dport == htons(port)))) 1367 return (type == ICMP_TIMXCEED? -1 : code + 1); 1368 break; 1369 default: 1370 /* this is some odd, user specified proto, 1371 * how do we check it? 1372 */ 1373 if (hip->ip_p == proto) 1374 return (type == ICMP_TIMXCEED? -1 : code + 1); 1375 } 1376 } 1377 if (verbose) { 1378 int i; 1379 in_addr_t *lp = (in_addr_t *)&icp->icmp_ip; 1380 1381 printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr)); 1382 printf(" to %s", inet_ntoa(ip->ip_dst)); 1383 printf(": icmp type %u (%s) code %d\n", type, pr_type(type), 1384 icp->icmp_code); 1385 for (i = 4; i < cc ; i += sizeof(in_addr_t)) 1386 printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++); 1387 } 1388 return (0); 1389 } 1390 1391 int 1392 packet_ok6(struct msghdr *mhdr, int cc, int seq, int iflag) 1393 { 1394 struct icmp6_hdr *icp; 1395 struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1396 u_char type, code; 1397 char *buf = (char *)mhdr->msg_iov[0].iov_base; 1398 struct cmsghdr *cm; 1399 int *hlimp; 1400 char hbuf[NI_MAXHOST]; 1401 int useicmp = (proto == IPPROTO_ICMP); 1402 1403 if (cc < sizeof(struct icmp6_hdr)) { 1404 if (verbose) { 1405 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1406 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1407 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1408 printf("data too short (%d bytes) from %s\n", cc, hbuf); 1409 } 1410 return(0); 1411 } 1412 icp = (struct icmp6_hdr *)buf; 1413 /* get optional information via advanced API */ 1414 rcvpktinfo = NULL; 1415 hlimp = NULL; 1416 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1417 cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 1418 if (cm->cmsg_level == IPPROTO_IPV6 && 1419 cm->cmsg_type == IPV6_PKTINFO && 1420 cm->cmsg_len == 1421 CMSG_LEN(sizeof(struct in6_pktinfo))) 1422 rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1423 1424 if (cm->cmsg_level == IPPROTO_IPV6 && 1425 cm->cmsg_type == IPV6_HOPLIMIT && 1426 cm->cmsg_len == CMSG_LEN(sizeof(int))) 1427 hlimp = (int *)CMSG_DATA(cm); 1428 } 1429 if (rcvpktinfo == NULL || hlimp == NULL) { 1430 warnx("failed to get received hop limit or packet info"); 1431 rcvhlim = 0; /*XXX*/ 1432 } else 1433 rcvhlim = *hlimp; 1434 1435 type = icp->icmp6_type; 1436 code = icp->icmp6_code; 1437 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 1438 || type == ICMP6_DST_UNREACH) { 1439 struct ip6_hdr *hip; 1440 struct udphdr *up; 1441 1442 hip = (struct ip6_hdr *)(icp + 1); 1443 if ((up = get_udphdr(hip, (u_char *)(buf + cc))) == NULL) { 1444 if (verbose) 1445 warnx("failed to get upper layer header"); 1446 return(0); 1447 } 1448 if (useicmp && 1449 ((struct icmp6_hdr *)up)->icmp6_id == ident && 1450 ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq)) 1451 return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1452 else if (!useicmp && 1453 up->uh_sport == htons(srcport) && 1454 ((iflag && up->uh_dport == htons(port + seq)) || 1455 (!iflag && up->uh_dport == htons(port)))) 1456 return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1457 } else if (useicmp && type == ICMP6_ECHO_REPLY) { 1458 if (icp->icmp6_id == ident && 1459 icp->icmp6_seq == htons(seq)) 1460 return (ICMP6_DST_UNREACH_NOPORT + 1); 1461 } 1462 if (verbose) { 1463 char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; 1464 u_int8_t *p; 1465 int i; 1466 1467 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1468 sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) 1469 strlcpy(sbuf, "invalid", sizeof(sbuf)); 1470 printf("\n%d bytes from %s to %s", cc, sbuf, 1471 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1472 dbuf, sizeof(dbuf)) : "?"); 1473 printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 1474 icp->icmp6_code); 1475 p = (u_int8_t *)(icp + 1); 1476 #define WIDTH 16 1477 for (i = 0; i < cc; i++) { 1478 if (i % WIDTH == 0) 1479 printf("%04x:", i); 1480 if (i % 4 == 0) 1481 printf(" "); 1482 printf("%02x", p[i]); 1483 if (i % WIDTH == WIDTH - 1) 1484 printf("\n"); 1485 } 1486 if (cc % WIDTH != 0) 1487 printf("\n"); 1488 } 1489 return(0); 1490 } 1491 1492 void 1493 print(struct sockaddr *from, int cc, const char *to) 1494 { 1495 char hbuf[NI_MAXHOST]; 1496 if (getnameinfo(from, from->sa_len, 1497 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1498 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1499 if (nflag) 1500 printf(" %s", hbuf); 1501 else 1502 printf(" %s (%s)", inetname(from), hbuf); 1503 1504 if (Aflag) 1505 print_asn((struct sockaddr_storage *)from); 1506 1507 if (verbose) 1508 printf(" %d bytes to %s", cc, to); 1509 } 1510 1511 /* 1512 * Increment pointer until find the UDP or ICMP header. 1513 */ 1514 struct udphdr * 1515 get_udphdr(struct ip6_hdr *ip6, u_char *lim) 1516 { 1517 u_char *cp = (u_char *)ip6, nh; 1518 int hlen; 1519 int useicmp = (proto == IPPROTO_ICMP); 1520 1521 if (cp + sizeof(*ip6) >= lim) 1522 return(NULL); 1523 1524 nh = ip6->ip6_nxt; 1525 cp += sizeof(struct ip6_hdr); 1526 1527 while (lim - cp >= 8) { 1528 switch (nh) { 1529 case IPPROTO_ESP: 1530 case IPPROTO_TCP: 1531 return(NULL); 1532 case IPPROTO_ICMPV6: 1533 return(useicmp ? (struct udphdr *)cp : NULL); 1534 case IPPROTO_UDP: 1535 return(useicmp ? NULL : (struct udphdr *)cp); 1536 case IPPROTO_FRAGMENT: 1537 hlen = sizeof(struct ip6_frag); 1538 nh = ((struct ip6_frag *)cp)->ip6f_nxt; 1539 break; 1540 case IPPROTO_AH: 1541 hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 1542 nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1543 break; 1544 default: 1545 hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 1546 nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1547 break; 1548 } 1549 1550 cp += hlen; 1551 } 1552 1553 return(NULL); 1554 } 1555 1556 void 1557 icmp_code(int af, int code, int *got_there, int *unreachable) 1558 { 1559 switch (af) { 1560 case AF_INET: 1561 icmp4_code(code, got_there, unreachable); 1562 break; 1563 case AF_INET6: 1564 icmp6_code(code, got_there, unreachable); 1565 break; 1566 default: 1567 errx(1, "unsupported AF: %d", af); 1568 break; 1569 } 1570 } 1571 1572 void 1573 icmp4_code(int code, int *got_there, int *unreachable) 1574 { 1575 struct ip *ip = (struct ip *)packet; 1576 1577 switch (code) { 1578 case ICMP_UNREACH_PORT: 1579 if (ip->ip_ttl <= 1) 1580 printf(" !"); 1581 ++(*got_there); 1582 break; 1583 case ICMP_UNREACH_NET: 1584 ++(*unreachable); 1585 printf(" !N"); 1586 break; 1587 case ICMP_UNREACH_HOST: 1588 ++(*unreachable); 1589 printf(" !H"); 1590 break; 1591 case ICMP_UNREACH_PROTOCOL: 1592 ++(*got_there); 1593 printf(" !P"); 1594 break; 1595 case ICMP_UNREACH_NEEDFRAG: 1596 ++(*unreachable); 1597 printf(" !F"); 1598 break; 1599 case ICMP_UNREACH_SRCFAIL: 1600 ++(*unreachable); 1601 printf(" !S"); 1602 break; 1603 case ICMP_UNREACH_FILTER_PROHIB: 1604 ++(*unreachable); 1605 printf(" !X"); 1606 break; 1607 case ICMP_UNREACH_NET_PROHIB: /*misuse*/ 1608 ++(*unreachable); 1609 printf(" !A"); 1610 break; 1611 case ICMP_UNREACH_HOST_PROHIB: 1612 ++(*unreachable); 1613 printf(" !C"); 1614 break; 1615 case ICMP_UNREACH_NET_UNKNOWN: 1616 case ICMP_UNREACH_HOST_UNKNOWN: 1617 ++(*unreachable); 1618 printf(" !U"); 1619 break; 1620 case ICMP_UNREACH_ISOLATED: 1621 ++(*unreachable); 1622 printf(" !I"); 1623 break; 1624 case ICMP_UNREACH_TOSNET: 1625 case ICMP_UNREACH_TOSHOST: 1626 ++(*unreachable); 1627 printf(" !T"); 1628 break; 1629 default: 1630 ++(*unreachable); 1631 printf(" !<%d>", code); 1632 break; 1633 } 1634 } 1635 1636 void 1637 icmp6_code(int code, int *got_there, int *unreachable) 1638 { 1639 switch (code) { 1640 case ICMP6_DST_UNREACH_NOROUTE: 1641 ++(*unreachable); 1642 printf(" !N"); 1643 break; 1644 case ICMP6_DST_UNREACH_ADMIN: 1645 ++(*unreachable); 1646 printf(" !P"); 1647 break; 1648 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 1649 ++(*unreachable); 1650 printf(" !S"); 1651 break; 1652 case ICMP6_DST_UNREACH_ADDR: 1653 ++(*unreachable); 1654 printf(" !A"); 1655 break; 1656 case ICMP6_DST_UNREACH_NOPORT: 1657 if (rcvhlim >= 0 && rcvhlim <= 1) 1658 printf(" !"); 1659 ++(*got_there); 1660 break; 1661 default: 1662 ++(*unreachable); 1663 printf(" !<%d>", code); 1664 break; 1665 } 1666 } 1667 1668 /* 1669 * Checksum routine for Internet Protocol family headers (C Version) 1670 */ 1671 u_short 1672 in_cksum(u_short *addr, int len) 1673 { 1674 u_short *w = addr, answer; 1675 int nleft = len, sum = 0; 1676 1677 /* 1678 * Our algorithm is simple, using a 32 bit accumulator (sum), 1679 * we add sequential 16 bit words to it, and at the end, fold 1680 * back all the carry bits from the top 16 bits into the lower 1681 * 16 bits. 1682 */ 1683 while (nleft > 1) { 1684 sum += *w++; 1685 nleft -= 2; 1686 } 1687 1688 /* mop up an odd byte, if necessary */ 1689 if (nleft == 1) 1690 sum += *(u_char *)w; 1691 1692 /* 1693 * add back carry outs from top 16 bits to low 16 bits 1694 */ 1695 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 1696 sum += (sum >> 16); /* add carry */ 1697 answer = ~sum; /* truncate to 16 bits */ 1698 return (answer); 1699 } 1700 1701 /* 1702 * Construct an Internet address representation. 1703 */ 1704 const char * 1705 inetname(struct sockaddr *sa) 1706 { 1707 static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1]; 1708 static int first = 1; 1709 char *cp; 1710 1711 if (first) { 1712 first = 0; 1713 if (gethostname(domain, sizeof(domain)) == 0 && 1714 (cp = strchr(domain, '.')) != NULL) 1715 (void) strlcpy(domain, cp + 1, sizeof(domain)); 1716 else 1717 domain[0] = 0; 1718 } 1719 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1720 NI_NAMEREQD) == 0) { 1721 if ((cp = strchr(line, '.')) != NULL && strcmp(cp + 1, 1722 domain) == 0) 1723 *cp = '\0'; 1724 return (line); 1725 } 1726 1727 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1728 NI_NUMERICHOST) != 0) 1729 return ("invalid"); 1730 return (line); 1731 } 1732 1733 void 1734 print_asn(struct sockaddr_storage *ss) 1735 { 1736 struct rrsetinfo *answers = NULL; 1737 int counter; 1738 const u_char *uaddr; 1739 char qbuf[MAXDNAME]; 1740 1741 switch (ss->ss_family) { 1742 case AF_INET: 1743 uaddr = (const u_char *)&((struct sockaddr_in *) ss)->sin_addr; 1744 if (snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u." 1745 "origin.asn.cymru.com", 1746 (uaddr[3] & 0xff), (uaddr[2] & 0xff), 1747 (uaddr[1] & 0xff), (uaddr[0] & 0xff)) >= sizeof (qbuf)) 1748 return; 1749 break; 1750 case AF_INET6: 1751 uaddr = (const u_char *)&((struct sockaddr_in6 *) ss)->sin6_addr; 1752 if (snprintf(qbuf, sizeof qbuf, 1753 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 1754 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 1755 "origin6.asn.cymru.com", 1756 (uaddr[15] & 0x0f), ((uaddr[15] >>4)& 0x0f), 1757 (uaddr[14] & 0x0f), ((uaddr[14] >>4)& 0x0f), 1758 (uaddr[13] & 0x0f), ((uaddr[13] >>4)& 0x0f), 1759 (uaddr[12] & 0x0f), ((uaddr[12] >>4)& 0x0f), 1760 (uaddr[11] & 0x0f), ((uaddr[11] >>4)& 0x0f), 1761 (uaddr[10] & 0x0f), ((uaddr[10] >>4)& 0x0f), 1762 (uaddr[9] & 0x0f), ((uaddr[9] >>4)& 0x0f), 1763 (uaddr[8] & 0x0f), ((uaddr[8] >>4)& 0x0f), 1764 (uaddr[7] & 0x0f), ((uaddr[7] >>4)& 0x0f), 1765 (uaddr[6] & 0x0f), ((uaddr[6] >>4)& 0x0f), 1766 (uaddr[5] & 0x0f), ((uaddr[5] >>4)& 0x0f), 1767 (uaddr[4] & 0x0f), ((uaddr[4] >>4)& 0x0f), 1768 (uaddr[3] & 0x0f), ((uaddr[3] >>4)& 0x0f), 1769 (uaddr[2] & 0x0f), ((uaddr[2] >>4)& 0x0f), 1770 (uaddr[1] & 0x0f), ((uaddr[1] >>4)& 0x0f), 1771 (uaddr[0] & 0x0f), ((uaddr[0] >>4)& 0x0f)) >= sizeof (qbuf)) 1772 return; 1773 break; 1774 default: 1775 return; 1776 } 1777 1778 if (getrrsetbyname(qbuf, C_IN, T_TXT, 0, &answers) != 0) 1779 return; 1780 for (counter = 0; counter < answers->rri_nrdatas; counter++) { 1781 char *p, *as = answers->rri_rdatas[counter].rdi_data; 1782 as++; /* skip first byte, it contains length */ 1783 if ((p = strchr(as,'|'))) { 1784 printf(counter ? ", " : " ["); 1785 p[-1] = 0; 1786 printf("AS%s", as); 1787 } 1788 } 1789 if (counter) 1790 printf("]"); 1791 1792 freerrset(answers); 1793 } 1794 1795 int 1796 map_tos(char *s, int *val) 1797 { 1798 /* DiffServ Codepoints and other TOS mappings */ 1799 const struct toskeywords { 1800 const char *keyword; 1801 int val; 1802 } *t, toskeywords[] = { 1803 { "af11", IPTOS_DSCP_AF11 }, 1804 { "af12", IPTOS_DSCP_AF12 }, 1805 { "af13", IPTOS_DSCP_AF13 }, 1806 { "af21", IPTOS_DSCP_AF21 }, 1807 { "af22", IPTOS_DSCP_AF22 }, 1808 { "af23", IPTOS_DSCP_AF23 }, 1809 { "af31", IPTOS_DSCP_AF31 }, 1810 { "af32", IPTOS_DSCP_AF32 }, 1811 { "af33", IPTOS_DSCP_AF33 }, 1812 { "af41", IPTOS_DSCP_AF41 }, 1813 { "af42", IPTOS_DSCP_AF42 }, 1814 { "af43", IPTOS_DSCP_AF43 }, 1815 { "critical", IPTOS_PREC_CRITIC_ECP }, 1816 { "cs0", IPTOS_DSCP_CS0 }, 1817 { "cs1", IPTOS_DSCP_CS1 }, 1818 { "cs2", IPTOS_DSCP_CS2 }, 1819 { "cs3", IPTOS_DSCP_CS3 }, 1820 { "cs4", IPTOS_DSCP_CS4 }, 1821 { "cs5", IPTOS_DSCP_CS5 }, 1822 { "cs6", IPTOS_DSCP_CS6 }, 1823 { "cs7", IPTOS_DSCP_CS7 }, 1824 { "ef", IPTOS_DSCP_EF }, 1825 { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 1826 { "lowdelay", IPTOS_LOWDELAY }, 1827 { "netcontrol", IPTOS_PREC_NETCONTROL }, 1828 { "reliability", IPTOS_RELIABILITY }, 1829 { "throughput", IPTOS_THROUGHPUT }, 1830 { NULL, -1 }, 1831 }; 1832 1833 for (t = toskeywords; t->keyword != NULL; t++) { 1834 if (strcmp(s, t->keyword) == 0) { 1835 *val = t->val; 1836 return (1); 1837 } 1838 } 1839 1840 return (0); 1841 } 1842 1843 void 1844 usage(void) 1845 { 1846 if (v6flag) { 1847 fprintf(stderr, "usage: traceroute6 [-AcDdIlnSv] [-f first_hop] " 1848 "[-m max_hop] [-p port]\n" 1849 "\t[-q nqueries] [-s src_addr] [-V rtable] [-w waittime] " 1850 "host\n\t[datalen]\n"); 1851 } else { 1852 fprintf(stderr, 1853 "usage: %s [-AcDdIlnSvx] [-f first_ttl] [-g gateway_addr] " 1854 "[-m max_ttl]\n" 1855 "\t[-P proto] [-p port] [-q nqueries] [-s src_addr]\n" 1856 "\t[-t toskeyword] " 1857 "[-V rtable] [-w waittime] host [datalen]\n", 1858 __progname); 1859 } 1860 exit(1); 1861 } 1862