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