]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/traceroute/traceroute.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / traceroute / traceroute.c
1 /*
2  * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #ifndef lint
23 static const char copyright[] =
24     "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
25 The Regents of the University of California.  All rights reserved.\n";
26 #if 0
27 static const char rcsid[] =
28     "@(#)$Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp $ (LBL)";
29 #endif
30 static const char rcsid[] =
31     "$FreeBSD$";
32 #endif
33
34 /*
35  * traceroute host  - trace the route ip packets follow going to "host".
36  *
37  * Attempt to trace the route an ip packet would follow to some
38  * internet host.  We find out intermediate hops by launching probe
39  * packets with a small ttl (time to live) then listening for an
40  * icmp "time exceeded" reply from a gateway.  We start our probes
41  * with a ttl of one and increase by one until we get an icmp "port
42  * unreachable" (which means we got to "host") or hit a max (which
43  * defaults to net.inet.ip.ttl hops & can be changed with the -m flag).
44  * Three probes (change with -q flag) are sent at each ttl setting and
45  * a line is printed showing the ttl, address of the gateway and
46  * round trip time of each probe.  If the probe answers come from
47  * different gateways, the address of each responding system will
48  * be printed.  If there is no response within a 5 sec. timeout
49  * interval (changed with the -w flag), a "*" is printed for that
50  * probe.
51  *
52  * Probe packets are UDP format.  We don't want the destination
53  * host to process them so the destination port is set to an
54  * unlikely value (if some clod on the destination is using that
55  * value, it can be changed with the -p flag).
56  *
57  * A sample use might be:
58  *
59  *     [yak 71]% traceroute nis.nsf.net.
60  *     traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
61  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
62  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
63  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
64  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
65  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
66  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
67  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
68  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
69  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
70  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
71  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
72  *
73  * Note that lines 2 & 3 are the same.  This is due to a buggy
74  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
75  * packets with a zero ttl.
76  *
77  * A more interesting example is:
78  *
79  *     [yak 72]% traceroute allspice.lcs.mit.edu.
80  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
81  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
82  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
83  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
84  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
85  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
86  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
87  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
88  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
89  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
90  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
91  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
92  *     12  * * *
93  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
94  *     14  * * *
95  *     15  * * *
96  *     16  * * *
97  *     17  * * *
98  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
99  *
100  * (I start to see why I'm having so much trouble with mail to
101  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
102  * either don't send ICMP "time exceeded" messages or send them
103  * with a ttl too small to reach us.  14 - 17 are running the
104  * MIT C Gateway code that doesn't send "time exceeded"s.  God
105  * only knows what's going on with 12.
106  *
107  * The silent gateway 12 in the above may be the result of a bug in
108  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
109  * sends an unreachable message using whatever ttl remains in the
110  * original datagram.  Since, for gateways, the remaining ttl is
111  * zero, the icmp "time exceeded" is guaranteed to not make it back
112  * to us.  The behavior of this bug is slightly more interesting
113  * when it appears on the destination system:
114  *
115  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
116  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
117  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
118  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
119  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
120  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
121  *      7  * * *
122  *      8  * * *
123  *      9  * * *
124  *     10  * * *
125  *     11  * * *
126  *     12  * * *
127  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
128  *
129  * Notice that there are 12 "gateways" (13 is the final
130  * destination) and exactly the last half of them are "missing".
131  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
132  * is using the ttl from our arriving datagram as the ttl in its
133  * icmp reply.  So, the reply will time out on the return path
134  * (with no notice sent to anyone since icmp's aren't sent for
135  * icmp's) until we probe with a ttl that's at least twice the path
136  * length.  I.e., rip is really only 7 hops away.  A reply that
137  * returns with a ttl of 1 is a clue this problem exists.
138  * Traceroute prints a "!" after the time if the ttl is <= 1.
139  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
140  * non-standard (HPUX) software, expect to see this problem
141  * frequently and/or take care picking the target host of your
142  * probes.
143  *
144  * Other possible annotations after the time are !H, !N, !P (got a host,
145  * network or protocol unreachable, respectively), !S or !F (source
146  * route failed or fragmentation needed -- neither of these should
147  * ever occur and the associated gateway is busted if you see one).  If
148  * almost all the probes result in some kind of unreachable, traceroute
149  * will give up and exit.
150  *
151  * Notes
152  * -----
153  * This program must be run by root or be setuid.  (I suggest that
154  * you *don't* make it setuid -- casual use could result in a lot
155  * of unnecessary traffic on our poor, congested nets.)
156  *
157  * This program requires a kernel mod that does not appear in any
158  * system available from Berkeley:  A raw ip socket using proto
159  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
160  * opposed to data to be wrapped in a ip datagram).  See the README
161  * file that came with the source to this program for a description
162  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
163  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
164  * MODIFIED TO RUN THIS PROGRAM.
165  *
166  * The udp port usage may appear bizarre (well, ok, it is bizarre).
167  * The problem is that an icmp message only contains 8 bytes of
168  * data from the original datagram.  8 bytes is the size of a udp
169  * header so, if we want to associate replies with the original
170  * datagram, the necessary information must be encoded into the
171  * udp header (the ip id could be used but there's no way to
172  * interlock with the kernel's assignment of ip id's and, anyway,
173  * it would have taken a lot more kernel hacking to allow this
174  * code to set the ip id).  So, to allow two or more users to
175  * use traceroute simultaneously, we use this task's pid as the
176  * source port (the high bit is set to move the port number out
177  * of the "likely" range).  To keep track of which probe is being
178  * replied to (so times and/or hop counts don't get confused by a
179  * reply that was delayed in transit), we increment the destination
180  * port number before each probe.
181  *
182  * Don't use this as a coding example.  I was trying to find a
183  * routing problem and this code sort-of popped out after 48 hours
184  * without sleep.  I was amazed it ever compiled, much less ran.
185  *
186  * I stole the idea for this program from Steve Deering.  Since
187  * the first release, I've learned that had I attended the right
188  * IETF working group meetings, I also could have stolen it from Guy
189  * Almes or Matt Mathis.  I don't know (or care) who came up with
190  * the idea first.  I envy the originators' perspicacity and I'm
191  * glad they didn't keep the idea a secret.
192  *
193  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
194  * enhancements to the original distribution.
195  *
196  * I've hacked up a round-trip-route version of this that works by
197  * sending a loose-source-routed udp datagram through the destination
198  * back to yourself.  Unfortunately, SO many gateways botch source
199  * routing, the thing is almost worthless.  Maybe one day...
200  *
201  *  -- Van Jacobson (van@ee.lbl.gov)
202  *     Tue Dec 20 03:50:13 PST 1988
203  */
204
205 #include <sys/param.h>
206 #include <sys/file.h>
207 #include <sys/ioctl.h>
208 #ifdef HAVE_SYS_SELECT_H
209 #include <sys/select.h>
210 #endif
211 #include <sys/socket.h>
212 #ifdef HAVE_SYS_SYSCTL_H
213 #include <sys/sysctl.h>
214 #endif
215 #include <sys/time.h>
216
217 #include <netinet/in_systm.h>
218 #include <netinet/in.h>
219 #include <netinet/ip.h>
220 #include <netinet/ip_var.h>
221 #include <netinet/ip_icmp.h>
222 #include <netinet/udp.h>
223 #include <netinet/udp_var.h>
224 #include <netinet/tcp.h>
225 #include <netinet/tcpip.h>
226
227 #include <arpa/inet.h>
228
229 #ifdef  IPSEC
230 #include <net/route.h>
231 #include <netipsec/ipsec.h>     /* XXX */
232 #endif  /* IPSEC */
233
234 #include <ctype.h>
235 #include <err.h>
236 #include <errno.h>
237 #include <fcntl.h>
238 #ifdef HAVE_MALLOC_H
239 #include <malloc.h>
240 #endif
241 #include <memory.h>
242 #include <netdb.h>
243 #include <stdio.h>
244 #include <stdlib.h>
245 #include <string.h>
246 #include <unistd.h>
247
248 #include "gnuc.h"
249 #ifdef HAVE_OS_PROTO_H
250 #include "os-proto.h"
251 #endif
252
253 /* rfc1716 */
254 #ifndef ICMP_UNREACH_FILTER_PROHIB
255 #define ICMP_UNREACH_FILTER_PROHIB      13      /* admin prohibited filter */
256 #endif
257 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
258 #define ICMP_UNREACH_HOST_PRECEDENCE    14      /* host precedence violation */
259 #endif
260 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
261 #define ICMP_UNREACH_PRECEDENCE_CUTOFF  15      /* precedence cutoff */
262 #endif
263
264 #include "findsaddr.h"
265 #include "ifaddrlist.h"
266 #include "as.h"
267 #include "traceroute.h"
268
269 /* Maximum number of gateways (include room for one noop) */
270 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
271
272 #ifndef MAXHOSTNAMELEN
273 #define MAXHOSTNAMELEN  64
274 #endif
275
276 #define Fprintf (void)fprintf
277 #define Printf (void)printf
278
279 /* What a GRE packet header looks like */
280 struct grehdr {
281         u_int16_t   flags;
282         u_int16_t   proto;
283         u_int16_t   length;     /* PPTP version of these fields */
284         u_int16_t   callId;
285 };
286 #ifndef IPPROTO_GRE
287 #define IPPROTO_GRE     47
288 #endif
289
290 /* For GRE, we prepare what looks like a PPTP packet */
291 #define GRE_PPTP_PROTO  0x880b
292
293 /* Host name and address list */
294 struct hostinfo {
295         char *name;
296         int n;
297         u_int32_t *addrs;
298 };
299
300 /* Data section of the probe packet */
301 struct outdata {
302         u_char seq;             /* sequence number of this packet */
303         u_char ttl;             /* ttl packet left with */
304         struct timeval tv;      /* time packet left */
305 };
306
307 #ifndef HAVE_ICMP_NEXTMTU
308 /* Path MTU Discovery (RFC1191) */
309 struct my_pmtu {
310         u_short ipm_void;
311         u_short ipm_nextmtu;
312 };
313 #endif
314
315 u_char  packet[512];            /* last inbound (icmp) packet */
316
317 struct ip *outip;               /* last output ip packet */
318 u_char *outp;           /* last output inner protocol packet */
319
320 struct ip *hip = NULL;          /* Quoted IP header */
321 int hiplen = 0;
322
323 /* loose source route gateway list (including room for final destination) */
324 u_int32_t gwlist[NGATEWAYS + 1];
325
326 int s;                          /* receive (icmp) socket file descriptor */
327 int sndsock;                    /* send (udp) socket file descriptor */
328
329 struct sockaddr whereto;        /* Who to try to reach */
330 struct sockaddr wherefrom;      /* Who we are */
331 int packlen;                    /* total length of packet */
332 int protlen;                    /* length of protocol part of packet */
333 int minpacket;                  /* min ip packet size */
334 int maxpacket = 32 * 1024;      /* max ip packet size */
335 int pmtu;                       /* Path MTU Discovery (RFC1191) */
336 u_int pausemsecs;
337
338 char *prog;
339 char *source;
340 char *hostname;
341 char *device;
342 static const char devnull[] = "/dev/null";
343
344 int nprobes = -1;
345 int max_ttl;
346 int first_ttl = 1;
347 u_short ident;
348 u_short port;                   /* protocol specific base "port" */
349
350 int options;                    /* socket options */
351 int verbose;
352 int waittime = 5;               /* time to wait for response (in seconds) */
353 int nflag;                      /* print addresses numerically */
354 int as_path;                    /* print as numbers for each hop */
355 char *as_server = NULL;
356 void *asn;
357 #ifdef CANT_HACK_IPCKSUM
358 int doipcksum = 0;              /* don't calculate ip checksums by default */
359 #else
360 int doipcksum = 1;              /* calculate ip checksums by default */
361 #endif
362 int optlen;                     /* length of ip options */
363 int fixedPort = 0;              /* Use fixed destination port for TCP and UDP */
364 int printdiff = 0;              /* Print the difference between sent and quoted */
365
366 extern int optind;
367 extern int opterr;
368 extern char *optarg;
369
370 /* Forwards */
371 double  deltaT(struct timeval *, struct timeval *);
372 void    freehostinfo(struct hostinfo *);
373 void    getaddr(u_int32_t *, char *);
374 struct  hostinfo *gethostinfo(char *);
375 u_short in_cksum(u_short *, int);
376 char    *inetname(struct in_addr);
377 int     main(int, char **);
378 u_short p_cksum(struct ip *, u_short *, int);
379 int     packet_ok(u_char *, int, struct sockaddr_in *, int);
380 char    *pr_type(u_char);
381 void    print(u_char *, int, struct sockaddr_in *);
382 #ifdef  IPSEC
383 int     setpolicy __P((int so, char *policy));
384 #endif
385 void    send_probe(int, int);
386 struct outproto *setproto(char *);
387 int     str2val(const char *, const char *, int, int);
388 void    tvsub(struct timeval *, struct timeval *);
389 void usage(void);
390 int     wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
391 void pkt_compare(const u_char *, int, const u_char *, int);
392 #ifndef HAVE_USLEEP
393 int     usleep(u_int);
394 #endif
395
396 void    udp_prep(struct outdata *);
397 int     udp_check(const u_char *, int);
398 void    tcp_prep(struct outdata *);
399 int     tcp_check(const u_char *, int);
400 void    gre_prep(struct outdata *);
401 int     gre_check(const u_char *, int);
402 void    gen_prep(struct outdata *);
403 int     gen_check(const u_char *, int);
404 void    icmp_prep(struct outdata *);
405 int     icmp_check(const u_char *, int);
406
407 /* Descriptor structure for each outgoing protocol we support */
408 struct outproto {
409         char    *name;          /* name of protocol */
410         const char *key;        /* An ascii key for the bytes of the header */
411         u_char  num;            /* IP protocol number */
412         u_short hdrlen;         /* max size of protocol header */
413         u_short port;           /* default base protocol-specific "port" */
414         void    (*prepare)(struct outdata *);
415                                 /* finish preparing an outgoing packet */
416         int     (*check)(const u_char *, int);
417                                 /* check an incoming packet */
418 };
419
420 /* List of supported protocols. The first one is the default. The last
421    one is the handler for generic protocols not explicitly listed. */
422 struct  outproto protos[] = {
423         {
424                 "udp",
425                 "spt dpt len sum",
426                 IPPROTO_UDP,
427                 sizeof(struct udphdr),
428                 32768 + 666,
429                 udp_prep,
430                 udp_check
431         },
432         {
433                 "tcp",
434                 "spt dpt seq     ack     xxflwin sum urp",
435                 IPPROTO_TCP,
436                 sizeof(struct tcphdr),
437                 32768 + 666,
438                 tcp_prep,
439                 tcp_check
440         },
441         {
442                 "gre",
443                 "flg pro len clid",
444                 IPPROTO_GRE,
445                 sizeof(struct grehdr),
446                 GRE_PPTP_PROTO,
447                 gre_prep,
448                 gre_check
449         },
450         {
451                 "icmp",
452                 "typ cod sum ",
453                 IPPROTO_ICMP,
454                 sizeof(struct icmp),
455                 0,
456                 icmp_prep,
457                 icmp_check
458         },
459         {
460                 NULL,
461                 NULL,
462                 0,
463                 2 * sizeof(u_short),
464                 0,
465                 gen_prep,
466                 gen_check
467         },
468 };
469 struct  outproto *proto = &protos[0];
470
471 const char *ip_hdr_key = "vhtslen id  off tlprsum srcip   dstip   opts";
472
473 int
474 main(int argc, char **argv)
475 {
476         register int op, code, n;
477         register char *cp;
478         register const char *err;
479         register u_int32_t *ap;
480         register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
481         register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
482         register struct hostinfo *hi;
483         int on = 1;
484         register struct protoent *pe;
485         register int ttl, probe, i;
486         register int seq = 0;
487         int tos = 0, settos = 0;
488         register int lsrr = 0;
489         register u_short off = 0;
490         struct ifaddrlist *al;
491         char errbuf[132];
492         int requestPort = -1;
493         int sump = 0;
494         int sockerrno;
495
496         /* Insure the socket fds won't be 0, 1 or 2 */
497         if (open(devnull, O_RDONLY) < 0 ||
498             open(devnull, O_RDONLY) < 0 ||
499             open(devnull, O_RDONLY) < 0) {
500                 Fprintf(stderr, "%s: open \"%s\": %s\n",
501                     prog, devnull, strerror(errno));
502                 exit(1);
503         }
504         /*
505          * Do the setuid-required stuff first, then lose priveleges ASAP.
506          * Do error checking for these two calls where they appeared in
507          * the original code.
508          */
509         cp = "icmp";
510         pe = getprotobyname(cp);
511         if (pe) {
512                 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
513                         sockerrno = errno;
514                 else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
515                         sockerrno = errno;
516         }
517
518         setuid(getuid());
519
520 #ifdef IPCTL_DEFTTL
521         {
522                 int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
523                 size_t sz = sizeof(max_ttl);
524
525                 if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
526                         perror("sysctl(net.inet.ip.ttl)");
527                         exit(1);
528                 }
529         }
530 #else
531         max_ttl = 30;
532 #endif
533
534         if (argv[0] == NULL)
535                 prog = "traceroute";
536         else if ((cp = strrchr(argv[0], '/')) != NULL)
537                 prog = cp + 1;
538         else
539                 prog = argv[0];
540
541         opterr = 0;
542         while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
543                 switch (op) {
544                 case 'a':
545                         as_path = 1;
546                         break;
547                         
548                 case 'A':
549                         as_path = 1;
550                         as_server = optarg;
551                         break;
552                             
553                 case 'd':
554                         options |= SO_DEBUG;
555                         break;
556
557                 case 'D':
558                         printdiff = 1;
559                         break;
560
561                 case 'e':
562                         fixedPort = 1;
563                         break;
564
565                 case 'f':
566                 case 'M':       /* FreeBSD compat. */
567                         first_ttl = str2val(optarg, "first ttl", 1, 255);
568                         break;
569
570                 case 'F':
571                         off = IP_DF;
572                         break;
573
574                 case 'g':
575                         if (lsrr >= NGATEWAYS) {
576                                 Fprintf(stderr,
577                                     "%s: No more than %d gateways\n",
578                                     prog, NGATEWAYS);
579                                 exit(1);
580                         }
581                         getaddr(gwlist + lsrr, optarg);
582                         ++lsrr;
583                         break;
584
585                 case 'i':
586                         device = optarg;
587                         break;
588
589                 case 'I':
590                         proto = setproto("icmp");
591                         break;
592
593                 case 'm':
594                         max_ttl = str2val(optarg, "max ttl", 1, 255);
595                         break;
596
597                 case 'n':
598                         ++nflag;
599                         break;
600
601                 case 'P':
602                         proto = setproto(optarg);
603                         break;
604
605                 case 'p':
606                         requestPort = (u_short)str2val(optarg, "port",
607                             1, (1 << 16) - 1);
608                         break;
609
610                 case 'q':
611                         nprobes = str2val(optarg, "nprobes", 1, -1);
612                         break;
613
614                 case 'r':
615                         options |= SO_DONTROUTE;
616                         break;
617
618                 case 's':
619                         /*
620                          * set the ip source address of the outbound
621                          * probe (e.g., on a multi-homed host).
622                          */
623                         source = optarg;
624                         break;
625
626                 case 'S':
627                         sump = 1;
628                         break;
629
630                 case 't':
631                         tos = str2val(optarg, "tos", 0, 255);
632                         ++settos;
633                         break;
634
635                 case 'v':
636                         ++verbose;
637                         break;
638
639                 case 'x':
640                         doipcksum = (doipcksum == 0);
641                         break;
642
643                 case 'w':
644                         waittime = str2val(optarg, "wait time",
645                             1, 24 * 60 * 60);
646                         break;
647
648                 case 'z':
649                         pausemsecs = str2val(optarg, "pause msecs",
650                             0, 60 * 60 * 1000);
651                         break;
652
653                 default:
654                         usage();
655                 }
656
657         /* Set requested port, if any, else default for this protocol */
658         port = (requestPort != -1) ? requestPort : proto->port;
659
660         if (nprobes == -1)
661                 nprobes = printdiff ? 1 : 3;
662
663         if (first_ttl > max_ttl) {
664                 Fprintf(stderr,
665                     "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
666                     prog, first_ttl, max_ttl);
667                 exit(1);
668         }
669
670         if (!doipcksum)
671                 Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
672
673         if (lsrr > 0)
674                 optlen = (lsrr + 1) * sizeof(gwlist[0]);
675         minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
676         packlen = minpacket;                    /* minimum sized packet */
677
678         /* Process destination and optional packet size */
679         switch (argc - optind) {
680
681         case 2:
682                 packlen = str2val(argv[optind + 1],
683                     "packet length", minpacket, maxpacket);
684                 /* Fall through */
685
686         case 1:
687                 hostname = argv[optind];
688                 hi = gethostinfo(hostname);
689                 setsin(to, hi->addrs[0]);
690                 if (hi->n > 1)
691                         Fprintf(stderr,
692                     "%s: Warning: %s has multiple addresses; using %s\n",
693                                 prog, hostname, inet_ntoa(to->sin_addr));
694                 hostname = hi->name;
695                 hi->name = NULL;
696                 freehostinfo(hi);
697                 break;
698
699         default:
700                 usage();
701         }
702
703 #ifdef HAVE_SETLINEBUF
704         setlinebuf (stdout);
705 #else
706         setvbuf(stdout, NULL, _IOLBF, 0);
707 #endif
708
709         protlen = packlen - sizeof(*outip) - optlen;
710
711         outip = (struct ip *)malloc((unsigned)packlen);
712         if (outip == NULL) {
713                 Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
714                 exit(1);
715         }
716         memset((char *)outip, 0, packlen);
717
718         outip->ip_v = IPVERSION;
719         if (settos)
720                 outip->ip_tos = tos;
721 #ifdef BYTESWAP_IP_HDR
722         outip->ip_len = htons(packlen);
723         outip->ip_off = htons(off);
724 #else
725         outip->ip_len = packlen;
726         outip->ip_off = off;
727 #endif
728         outip->ip_p = proto->num;
729         outp = (u_char *)(outip + 1);
730 #ifdef HAVE_RAW_OPTIONS
731         if (lsrr > 0) {
732                 register u_char *optlist;
733
734                 optlist = outp;
735                 outp += optlen;
736
737                 /* final hop */
738                 gwlist[lsrr] = to->sin_addr.s_addr;
739
740                 outip->ip_dst.s_addr = gwlist[0];
741
742                 /* force 4 byte alignment */
743                 optlist[0] = IPOPT_NOP;
744                 /* loose source route option */
745                 optlist[1] = IPOPT_LSRR;
746                 i = lsrr * sizeof(gwlist[0]);
747                 optlist[2] = i + 3;
748                 /* Pointer to LSRR addresses */
749                 optlist[3] = IPOPT_MINOFF;
750                 memcpy(optlist + 4, gwlist + 1, i);
751         } else
752 #endif
753                 outip->ip_dst = to->sin_addr;
754
755         outip->ip_hl = (outp - (u_char *)outip) >> 2;
756         ident = (getpid() & 0xffff) | 0x8000;
757
758         if (pe == NULL) {
759                 Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
760                 exit(1);
761         }
762         if (s < 0) {
763                 errno = sockerrno;
764                 Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
765                 exit(1);
766         }
767         if (options & SO_DEBUG)
768                 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
769                     sizeof(on));
770         if (options & SO_DONTROUTE)
771                 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
772                     sizeof(on));
773
774 #if     defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
775         if (setpolicy(s, "in bypass") < 0)
776                 errx(1, "%s", ipsec_strerror());
777
778         if (setpolicy(s, "out bypass") < 0)
779                 errx(1, "%s", ipsec_strerror());
780 #endif  /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
781
782         if (sndsock < 0) {
783                 errno = sockerrno;
784                 Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
785                 exit(1);
786         }
787
788 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
789         if (lsrr > 0) {
790                 u_char optlist[MAX_IPOPTLEN];
791
792                 cp = "ip";
793                 if ((pe = getprotobyname(cp)) == NULL) {
794                         Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
795                         exit(1);
796                 }
797
798                 /* final hop */
799                 gwlist[lsrr] = to->sin_addr.s_addr;
800                 ++lsrr;
801
802                 /* force 4 byte alignment */
803                 optlist[0] = IPOPT_NOP;
804                 /* loose source route option */
805                 optlist[1] = IPOPT_LSRR;
806                 i = lsrr * sizeof(gwlist[0]);
807                 optlist[2] = i + 3;
808                 /* Pointer to LSRR addresses */
809                 optlist[3] = IPOPT_MINOFF;
810                 memcpy(optlist + 4, gwlist, i);
811
812                 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
813                     (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
814                         Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
815                             prog, strerror(errno));
816                         exit(1);
817                     }
818         }
819 #endif
820
821 #ifdef SO_SNDBUF
822         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
823             sizeof(packlen)) < 0) {
824                 Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
825                 exit(1);
826         }
827 #endif
828 #ifdef IP_HDRINCL
829         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
830             sizeof(on)) < 0) {
831                 Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
832                 exit(1);
833         }
834 #else
835 #ifdef IP_TOS
836         if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
837             (char *)&tos, sizeof(tos)) < 0) {
838                 Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
839                     prog, tos, strerror(errno));
840                 exit(1);
841         }
842 #endif
843 #endif
844         if (options & SO_DEBUG)
845                 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
846                     sizeof(on));
847         if (options & SO_DONTROUTE)
848                 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
849                     sizeof(on));
850
851         /* Get the interface address list */
852         n = ifaddrlist(&al, errbuf);
853         if (n < 0) {
854                 Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
855                 exit(1);
856         }
857         if (n == 0) {
858                 Fprintf(stderr,
859                     "%s: Can't find any network interfaces\n", prog);
860                 exit(1);
861         }
862
863         /* Look for a specific device */
864         if (device != NULL) {
865                 for (i = n; i > 0; --i, ++al)
866                         if (strcmp(device, al->device) == 0)
867                                 break;
868                 if (i <= 0) {
869                         Fprintf(stderr, "%s: Can't find interface %.32s\n",
870                             prog, device);
871                         exit(1);
872                 }
873         }
874
875         /* Determine our source address */
876         if (source == NULL) {
877                 /*
878                  * If a device was specified, use the interface address.
879                  * Otherwise, try to determine our source address.
880                  */
881                 if (device != NULL)
882                         setsin(from, al->addr);
883                 else if ((err = findsaddr(to, from)) != NULL) {
884                         Fprintf(stderr, "%s: findsaddr: %s\n",
885                             prog, err);
886                         exit(1);
887                 }
888         } else {
889                 hi = gethostinfo(source);
890                 source = hi->name;
891                 hi->name = NULL;
892                 /*
893                  * If the device was specified make sure it
894                  * corresponds to the source address specified.
895                  * Otherwise, use the first address (and warn if
896                  * there are more than one).
897                  */
898                 if (device != NULL) {
899                         for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
900                                 if (*ap == al->addr)
901                                         break;
902                         if (i <= 0) {
903                                 Fprintf(stderr,
904                                     "%s: %s is not on interface %.32s\n",
905                                     prog, source, device);
906                                 exit(1);
907                         }
908                         setsin(from, *ap);
909                 } else {
910                         setsin(from, hi->addrs[0]);
911                         if (hi->n > 1)
912                                 Fprintf(stderr,
913                         "%s: Warning: %s has multiple addresses; using %s\n",
914                                     prog, source, inet_ntoa(from->sin_addr));
915                 }
916                 freehostinfo(hi);
917         }
918
919         outip->ip_src = from->sin_addr;
920
921         /* Check the source address (-s), if any, is valid */
922         if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
923                 Fprintf(stderr, "%s: bind: %s\n",
924                     prog, strerror(errno));
925                 exit (1);
926         }
927
928         if (as_path) {
929                 asn = as_setup(as_server);
930                 if (asn == NULL) {
931                         Fprintf(stderr, "%s: as_setup failed, AS# lookups"
932                             " disabled\n", prog);
933                         (void)fflush(stderr);
934                         as_path = 0;
935                 }
936         }
937         
938 #if     defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
939         if (setpolicy(sndsock, "in bypass") < 0)
940                 errx(1, "%s", ipsec_strerror());
941
942         if (setpolicy(sndsock, "out bypass") < 0)
943                 errx(1, "%s", ipsec_strerror());
944 #endif  /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
945
946         Fprintf(stderr, "%s to %s (%s)",
947             prog, hostname, inet_ntoa(to->sin_addr));
948         if (source)
949                 Fprintf(stderr, " from %s", source);
950         Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
951         (void)fflush(stderr);
952
953         for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
954                 u_int32_t lastaddr = 0;
955                 int gotlastaddr = 0;
956                 int got_there = 0;
957                 int unreachable = 0;
958                 int sentfirst = 0;
959                 int loss;
960
961                 Printf("%2d ", ttl);
962                 for (probe = 0, loss = 0; probe < nprobes; ++probe) {
963                         register int cc;
964                         struct timeval t1, t2;
965                         struct timezone tz;
966                         register struct ip *ip;
967                         struct outdata outdata;
968
969                         if (sentfirst && pausemsecs > 0)
970                                 usleep(pausemsecs * 1000);
971                         /* Prepare outgoing data */
972                         outdata.seq = ++seq;
973                         outdata.ttl = ttl;
974
975                         /* Avoid alignment problems by copying bytewise: */
976                         (void)gettimeofday(&t1, &tz);
977                         memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
978
979                         /* Finalize and send packet */
980                         (*proto->prepare)(&outdata);
981                         send_probe(seq, ttl);
982                         ++sentfirst;
983
984                         /* Wait for a reply */
985                         while ((cc = wait_for_reply(s, from, &t1)) != 0) {
986                                 double T;
987                                 int precis;
988
989                                 (void)gettimeofday(&t2, &tz);
990                                 i = packet_ok(packet, cc, from, seq);
991                                 /* Skip short packet */
992                                 if (i == 0)
993                                         continue;
994                                 if (!gotlastaddr ||
995                                     from->sin_addr.s_addr != lastaddr) {
996                                         if (gotlastaddr) printf("\n   ");
997                                         print(packet, cc, from);
998                                         lastaddr = from->sin_addr.s_addr;
999                                         ++gotlastaddr;
1000                                 }
1001                                 T = deltaT(&t1, &t2);
1002 #ifdef SANE_PRECISION
1003                                 if (T >= 1000.0)
1004                                         precis = 0;
1005                                 else if (T >= 100.0)
1006                                         precis = 1;
1007                                 else if (T >= 10.0)
1008                                         precis = 2;
1009                                 else
1010 #endif
1011                                         precis = 3;
1012                                 Printf("  %.*f ms", precis, T);
1013                                 if (printdiff) {
1014                                         Printf("\n");
1015                                         Printf("%*.*s%s\n",
1016                                             -(outip->ip_hl << 3),
1017                                             outip->ip_hl << 3,
1018                                             ip_hdr_key,
1019                                             proto->key);
1020                                         pkt_compare((void *)outip, packlen,
1021                                             (void *)hip, hiplen);
1022                                 }
1023                                 if (i == -2) {
1024 #ifndef ARCHAIC
1025                                         ip = (struct ip *)packet;
1026                                         if (ip->ip_ttl <= 1)
1027                                                 Printf(" !");
1028 #endif
1029                                         ++got_there;
1030                                         break;
1031                                 }
1032                                 /* time exceeded in transit */
1033                                 if (i == -1)
1034                                         break;
1035                                 code = i - 1;
1036                                 switch (code) {
1037
1038                                 case ICMP_UNREACH_PORT:
1039 #ifndef ARCHAIC
1040                                         ip = (struct ip *)packet;
1041                                         if (ip->ip_ttl <= 1)
1042                                                 Printf(" !");
1043 #endif
1044                                         ++got_there;
1045                                         break;
1046
1047                                 case ICMP_UNREACH_NET:
1048                                         ++unreachable;
1049                                         Printf(" !N");
1050                                         break;
1051
1052                                 case ICMP_UNREACH_HOST:
1053                                         ++unreachable;
1054                                         Printf(" !H");
1055                                         break;
1056
1057                                 case ICMP_UNREACH_PROTOCOL:
1058                                         ++got_there;
1059                                         Printf(" !P");
1060                                         break;
1061
1062                                 case ICMP_UNREACH_NEEDFRAG:
1063                                         ++unreachable;
1064                                         Printf(" !F-%d", pmtu);
1065                                         break;
1066
1067                                 case ICMP_UNREACH_SRCFAIL:
1068                                         ++unreachable;
1069                                         Printf(" !S");
1070                                         break;
1071
1072                                 case ICMP_UNREACH_NET_UNKNOWN:
1073                                         ++unreachable;
1074                                         Printf(" !U");
1075                                         break;
1076
1077                                 case ICMP_UNREACH_HOST_UNKNOWN:
1078                                         ++unreachable;
1079                                         Printf(" !W");
1080                                         break;
1081
1082                                 case ICMP_UNREACH_ISOLATED:
1083                                         ++unreachable;
1084                                         Printf(" !I");
1085                                         break;
1086
1087                                 case ICMP_UNREACH_NET_PROHIB:
1088                                         ++unreachable;
1089                                         Printf(" !A");
1090                                         break;
1091
1092                                 case ICMP_UNREACH_HOST_PROHIB:
1093                                         ++unreachable;
1094                                         Printf(" !Z");
1095                                         break;
1096
1097                                 case ICMP_UNREACH_TOSNET:
1098                                         ++unreachable;
1099                                         Printf(" !Q");
1100                                         break;
1101
1102                                 case ICMP_UNREACH_TOSHOST:
1103                                         ++unreachable;
1104                                         Printf(" !T");
1105                                         break;
1106
1107                                 case ICMP_UNREACH_FILTER_PROHIB:
1108                                         ++unreachable;
1109                                         Printf(" !X");
1110                                         break;
1111
1112                                 case ICMP_UNREACH_HOST_PRECEDENCE:
1113                                         ++unreachable;
1114                                         Printf(" !V");
1115                                         break;
1116
1117                                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1118                                         ++unreachable;
1119                                         Printf(" !C");
1120                                         break;
1121
1122                                 default:
1123                                         ++unreachable;
1124                                         Printf(" !<%d>", code);
1125                                         break;
1126                                 }
1127                                 break;
1128                         }
1129                         if (cc == 0) {
1130                                 loss++;
1131                                 Printf(" *");
1132                         }
1133                         (void)fflush(stdout);
1134                 }
1135                 if (sump) {
1136                         Printf(" (%d%% loss)", (loss * 100) / nprobes);
1137                 }
1138                 putchar('\n');
1139                 if (got_there ||
1140                     (unreachable > 0 && unreachable >= nprobes - 1))
1141                         break;
1142         }
1143         if (as_path)
1144                 as_shutdown(asn);
1145         exit(0);
1146 }
1147
1148 int
1149 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
1150     register const struct timeval *tp)
1151 {
1152         fd_set *fdsp;
1153         size_t nfds;
1154         struct timeval now, wait;
1155         struct timezone tz;
1156         register int cc = 0;
1157         register int error;
1158         int fromlen = sizeof(*fromp);
1159
1160         nfds = howmany(sock + 1, NFDBITS);
1161         if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
1162                 err(1, "malloc");
1163         memset(fdsp, 0, nfds * sizeof(fd_mask));
1164         FD_SET(sock, fdsp);
1165
1166         wait.tv_sec = tp->tv_sec + waittime;
1167         wait.tv_usec = tp->tv_usec;
1168         (void)gettimeofday(&now, &tz);
1169         tvsub(&wait, &now);
1170         if (wait.tv_sec < 0) {
1171                 wait.tv_sec = 0;
1172                 wait.tv_usec = 1;
1173         }
1174
1175         error = select(sock + 1, fdsp, NULL, NULL, &wait);
1176         if (error == -1 && errno == EINVAL) {
1177                 Fprintf(stderr, "%s: botched select() args\n", prog);
1178                 exit(1);
1179         }
1180         if (error > 0)
1181                 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
1182                             (struct sockaddr *)fromp, &fromlen);
1183
1184         free(fdsp);
1185         return(cc);
1186 }
1187
1188 void
1189 send_probe(int seq, int ttl)
1190 {
1191         register int cc;
1192
1193         outip->ip_ttl = ttl;
1194         outip->ip_id = htons(ident + seq);
1195
1196         /* XXX undocumented debugging hack */
1197         if (verbose > 1) {
1198                 register const u_short *sp;
1199                 register int nshorts, i;
1200
1201                 sp = (u_short *)outip;
1202                 nshorts = (u_int)packlen / sizeof(u_short);
1203                 i = 0;
1204                 Printf("[ %d bytes", packlen);
1205                 while (--nshorts >= 0) {
1206                         if ((i++ % 8) == 0)
1207                                 Printf("\n\t");
1208                         Printf(" %04x", ntohs(*sp++));
1209                 }
1210                 if (packlen & 1) {
1211                         if ((i % 8) == 0)
1212                                 Printf("\n\t");
1213                         Printf(" %02x", *(u_char *)sp);
1214                 }
1215                 Printf("]\n");
1216         }
1217
1218 #if !defined(IP_HDRINCL) && defined(IP_TTL)
1219         if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1220             (char *)&ttl, sizeof(ttl)) < 0) {
1221                 Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1222                     prog, ttl, strerror(errno));
1223                 exit(1);
1224         }
1225 #endif
1226
1227         cc = sendto(sndsock, (char *)outip,
1228             packlen, 0, &whereto, sizeof(whereto));
1229         if (cc < 0 || cc != packlen)  {
1230                 if (cc < 0)
1231                         Fprintf(stderr, "%s: sendto: %s\n",
1232                             prog, strerror(errno));
1233                 Printf("%s: wrote %s %d chars, ret=%d\n",
1234                     prog, hostname, packlen, cc);
1235                 (void)fflush(stdout);
1236         }
1237 }
1238
1239 #if     defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
1240 int
1241 setpolicy(so, policy)
1242         int so;
1243         char *policy;
1244 {
1245         char *buf;
1246
1247         buf = ipsec_set_policy(policy, strlen(policy));
1248         if (buf == NULL) {
1249                 warnx("%s", ipsec_strerror());
1250                 return -1;
1251         }
1252         (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
1253                 buf, ipsec_get_policylen(buf));
1254
1255         free(buf);
1256
1257         return 0;
1258 }
1259 #endif
1260
1261 double
1262 deltaT(struct timeval *t1p, struct timeval *t2p)
1263 {
1264         register double dt;
1265
1266         dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
1267              (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
1268         return (dt);
1269 }
1270
1271 /*
1272  * Convert an ICMP "type" field to a printable string.
1273  */
1274 char *
1275 pr_type(register u_char t)
1276 {
1277         static char *ttab[] = {
1278         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
1279         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
1280         "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
1281         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
1282         "Info Reply"
1283         };
1284
1285         if (t > 16)
1286                 return("OUT-OF-RANGE");
1287
1288         return(ttab[t]);
1289 }
1290
1291 int
1292 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
1293     register int seq)
1294 {
1295         register struct icmp *icp;
1296         register u_char type, code;
1297         register int hlen;
1298 #ifndef ARCHAIC
1299         register struct ip *ip;
1300
1301         ip = (struct ip *) buf;
1302         hlen = ip->ip_hl << 2;
1303         if (cc < hlen + ICMP_MINLEN) {
1304                 if (verbose)
1305                         Printf("packet too short (%d bytes) from %s\n", cc,
1306                                 inet_ntoa(from->sin_addr));
1307                 return (0);
1308         }
1309         cc -= hlen;
1310         icp = (struct icmp *)(buf + hlen);
1311 #else
1312         icp = (struct icmp *)buf;
1313 #endif
1314         type = icp->icmp_type;
1315         code = icp->icmp_code;
1316         /* Path MTU Discovery (RFC1191) */
1317         if (code != ICMP_UNREACH_NEEDFRAG)
1318                 pmtu = 0;
1319         else {
1320 #ifdef HAVE_ICMP_NEXTMTU
1321                 pmtu = ntohs(icp->icmp_nextmtu);
1322 #else
1323                 pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1324 #endif
1325         }
1326         if (type == ICMP_ECHOREPLY
1327             && proto->num == IPPROTO_ICMP
1328             && (*proto->check)((u_char *)icp, (u_char)seq))
1329                 return -2;
1330         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
1331             type == ICMP_UNREACH) {
1332                 u_char *inner;
1333
1334                 hip = &icp->icmp_ip;
1335                 hiplen = ((u_char *)icp + cc) - (u_char *)hip;
1336                 hlen = hip->ip_hl << 2;
1337                 inner = (u_char *)((u_char *)hip + hlen);
1338                 if (hlen + 12 <= cc
1339                     && hip->ip_p == proto->num
1340                     && (*proto->check)(inner, (u_char)seq))
1341                         return (type == ICMP_TIMXCEED ? -1 : code + 1);
1342         }
1343 #ifndef ARCHAIC
1344         if (verbose) {
1345                 register int i;
1346                 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
1347
1348                 Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
1349                 Printf("%s: icmp type %d (%s) code %d\n",
1350                     inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1351                 for (i = 4; i < cc ; i += sizeof(*lp))
1352                         Printf("%2d: x%8.8x\n", i, *lp++);
1353         }
1354 #endif
1355         return(0);
1356 }
1357
1358 void
1359 icmp_prep(struct outdata *outdata)
1360 {
1361         struct icmp *const icmpheader = (struct icmp *) outp;
1362
1363         icmpheader->icmp_type = ICMP_ECHO;
1364         icmpheader->icmp_id = htons(ident);
1365         icmpheader->icmp_seq = htons(outdata->seq);
1366         icmpheader->icmp_cksum = 0;
1367         icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
1368         if (icmpheader->icmp_cksum == 0)
1369                 icmpheader->icmp_cksum = 0xffff;
1370 }
1371
1372 int
1373 icmp_check(const u_char *data, int seq)
1374 {
1375         struct icmp *const icmpheader = (struct icmp *) data;
1376
1377         return (icmpheader->icmp_id == htons(ident)
1378             && icmpheader->icmp_seq == htons(seq));
1379 }
1380
1381 void
1382 udp_prep(struct outdata *outdata)
1383 {
1384         struct udphdr *const outudp = (struct udphdr *) outp;
1385
1386         outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1387         outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1388         outudp->uh_ulen = htons((u_short)protlen);
1389         outudp->uh_sum = 0;
1390         if (doipcksum) {
1391             u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
1392             outudp->uh_sum = (sum) ? sum : 0xffff;
1393         }
1394
1395         return;
1396 }
1397
1398 int
1399 udp_check(const u_char *data, int seq)
1400 {
1401         struct udphdr *const udp = (struct udphdr *) data;
1402
1403         return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1404             ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
1405 }
1406
1407 void
1408 tcp_prep(struct outdata *outdata)
1409 {
1410         struct tcphdr *const tcp = (struct tcphdr *) outp;
1411
1412         tcp->th_sport = htons(ident);
1413         tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1414         tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
1415             (fixedPort ? outdata->seq : 0));
1416         tcp->th_ack = 0;
1417         tcp->th_off = 5;
1418         tcp->th_flags = TH_SYN;
1419         tcp->th_sum = 0;
1420
1421         if (doipcksum) {
1422             u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
1423             tcp->th_sum = (sum) ? sum : 0xffff;
1424         }
1425 }
1426
1427 int
1428 tcp_check(const u_char *data, int seq)
1429 {
1430         struct tcphdr *const tcp = (struct tcphdr *) data;
1431
1432         return (ntohs(tcp->th_sport) == ident
1433             && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
1434             && tcp->th_seq == (ident << 16) | (port + seq);
1435 }
1436
1437 void
1438 gre_prep(struct outdata *outdata)
1439 {
1440         struct grehdr *const gre = (struct grehdr *) outp;
1441
1442         gre->flags = htons(0x2001);
1443         gre->proto = htons(port);
1444         gre->length = 0;
1445         gre->callId = htons(ident + outdata->seq);
1446 }
1447
1448 int
1449 gre_check(const u_char *data, int seq)
1450 {
1451         struct grehdr *const gre = (struct grehdr *) data;
1452
1453         return(ntohs(gre->proto) == port
1454             && ntohs(gre->callId) == ident + seq);
1455 }
1456
1457 void
1458 gen_prep(struct outdata *outdata)
1459 {
1460         u_int16_t *const ptr = (u_int16_t *) outp;
1461
1462         ptr[0] = htons(ident);
1463         ptr[1] = htons(port + outdata->seq);
1464 }
1465
1466 int
1467 gen_check(const u_char *data, int seq)
1468 {
1469         u_int16_t *const ptr = (u_int16_t *) data;
1470
1471         return(ntohs(ptr[0]) == ident
1472             && ntohs(ptr[1]) == port + seq);
1473 }
1474
1475 void
1476 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
1477 {
1478         register struct ip *ip;
1479         register int hlen;
1480         char addr[INET_ADDRSTRLEN];
1481
1482         ip = (struct ip *) buf;
1483         hlen = ip->ip_hl << 2;
1484         cc -= hlen;
1485
1486         strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
1487
1488         if (as_path)
1489                 Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
1490
1491         if (nflag)
1492                 Printf(" %s", addr);
1493         else
1494                 Printf(" %s (%s)", inetname(from->sin_addr), addr);
1495
1496         if (verbose)
1497                 Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
1498 }
1499
1500 /*
1501  * Checksum routine for UDP and TCP headers.
1502  */
1503 u_short 
1504 p_cksum(struct ip *ip, u_short *data, int len)
1505 {
1506         static struct ipovly ipo;
1507         u_short sumh, sumd;
1508         u_long sumt;
1509
1510         ipo.ih_pr = ip->ip_p;
1511         ipo.ih_len = htons(len);
1512         ipo.ih_src = ip->ip_src;
1513         ipo.ih_dst = ip->ip_dst;
1514
1515         sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
1516         sumd = in_cksum((u_short*)data, len);         /* payload data cksum */
1517         sumt = (sumh << 16) | (sumd);
1518
1519         return ~in_cksum((u_short*)&sumt, sizeof(sumt));
1520 }
1521
1522 /*
1523  * Checksum routine for Internet Protocol family headers (C Version)
1524  */
1525 u_short
1526 in_cksum(register u_short *addr, register int len)
1527 {
1528         register int nleft = len;
1529         register u_short *w = addr;
1530         register u_short answer;
1531         register int sum = 0;
1532
1533         /*
1534          *  Our algorithm is simple, using a 32 bit accumulator (sum),
1535          *  we add sequential 16 bit words to it, and at the end, fold
1536          *  back all the carry bits from the top 16 bits into the lower
1537          *  16 bits.
1538          */
1539         while (nleft > 1)  {
1540                 sum += *w++;
1541                 nleft -= 2;
1542         }
1543
1544         /* mop up an odd byte, if necessary */
1545         if (nleft == 1)
1546                 sum += *(u_char *)w;
1547
1548         /*
1549          * add back carry outs from top 16 bits to low 16 bits
1550          */
1551         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
1552         sum += (sum >> 16);                     /* add carry */
1553         answer = ~sum;                          /* truncate to 16 bits */
1554         return (answer);
1555 }
1556
1557 /*
1558  * Subtract 2 timeval structs:  out = out - in.
1559  * Out is assumed to be within about LONG_MAX seconds of in.
1560  */
1561 void
1562 tvsub(register struct timeval *out, register struct timeval *in)
1563 {
1564
1565         if ((out->tv_usec -= in->tv_usec) < 0)   {
1566                 --out->tv_sec;
1567                 out->tv_usec += 1000000;
1568         }
1569         out->tv_sec -= in->tv_sec;
1570 }
1571
1572 /*
1573  * Construct an Internet address representation.
1574  * If the nflag has been supplied, give
1575  * numeric value, otherwise try for symbolic name.
1576  */
1577 char *
1578 inetname(struct in_addr in)
1579 {
1580         register char *cp;
1581         register struct hostent *hp;
1582         static int first = 1;
1583         static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
1584
1585         if (first && !nflag) {
1586                 first = 0;
1587                 if (gethostname(domain, sizeof(domain) - 1) < 0)
1588                         domain[0] = '\0';
1589                 else {
1590                         cp = strchr(domain, '.');
1591                         if (cp == NULL) {
1592                                 hp = gethostbyname(domain);
1593                                 if (hp != NULL)
1594                                         cp = strchr(hp->h_name, '.');
1595                         }
1596                         if (cp == NULL)
1597                                 domain[0] = '\0';
1598                         else {
1599                                 ++cp;
1600                                 (void)strncpy(domain, cp, sizeof(domain) - 1);
1601                                 domain[sizeof(domain) - 1] = '\0';
1602                         }
1603                 }
1604         }
1605         if (!nflag && in.s_addr != INADDR_ANY) {
1606                 hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1607                 if (hp != NULL) {
1608                         if ((cp = strchr(hp->h_name, '.')) != NULL &&
1609                             strcmp(cp + 1, domain) == 0)
1610                                 *cp = '\0';
1611                         (void)strncpy(line, hp->h_name, sizeof(line) - 1);
1612                         line[sizeof(line) - 1] = '\0';
1613                         return (line);
1614                 }
1615         }
1616         return (inet_ntoa(in));
1617 }
1618
1619 struct hostinfo *
1620 gethostinfo(register char *hostname)
1621 {
1622         register int n;
1623         register struct hostent *hp;
1624         register struct hostinfo *hi;
1625         register char **p;
1626         register u_int32_t addr, *ap;
1627
1628         if (strlen(hostname) > 64) {
1629                 Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1630                     prog, hostname);
1631                 exit(1);
1632         }
1633         hi = calloc(1, sizeof(*hi));
1634         if (hi == NULL) {
1635                 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1636                 exit(1);
1637         }
1638         addr = inet_addr(hostname);
1639         if ((int32_t)addr != -1) {
1640                 hi->name = strdup(hostname);
1641                 hi->n = 1;
1642                 hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1643                 if (hi->addrs == NULL) {
1644                         Fprintf(stderr, "%s: calloc %s\n",
1645                             prog, strerror(errno));
1646                         exit(1);
1647                 }
1648                 hi->addrs[0] = addr;
1649                 return (hi);
1650         }
1651
1652         hp = gethostbyname(hostname);
1653         if (hp == NULL) {
1654                 Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
1655                 exit(1);
1656         }
1657         if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
1658                 Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
1659                 exit(1);
1660         }
1661         hi->name = strdup(hp->h_name);
1662         for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1663                 continue;
1664         hi->n = n;
1665         hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1666         if (hi->addrs == NULL) {
1667                 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1668                 exit(1);
1669         }
1670         for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1671                 memcpy(ap, *p, sizeof(*ap));
1672         return (hi);
1673 }
1674
1675 void
1676 freehostinfo(register struct hostinfo *hi)
1677 {
1678         if (hi->name != NULL) {
1679                 free(hi->name);
1680                 hi->name = NULL;
1681         }
1682         free((char *)hi->addrs);
1683         free((char *)hi);
1684 }
1685
1686 void
1687 getaddr(register u_int32_t *ap, register char *hostname)
1688 {
1689         register struct hostinfo *hi;
1690
1691         hi = gethostinfo(hostname);
1692         *ap = hi->addrs[0];
1693         freehostinfo(hi);
1694 }
1695
1696 void
1697 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
1698 {
1699
1700         memset(sin, 0, sizeof(*sin));
1701 #ifdef HAVE_SOCKADDR_SA_LEN
1702         sin->sin_len = sizeof(*sin);
1703 #endif
1704         sin->sin_family = AF_INET;
1705         sin->sin_addr.s_addr = addr;
1706 }
1707
1708 /* String to value with optional min and max. Handles decimal and hex. */
1709 int
1710 str2val(register const char *str, register const char *what,
1711     register int mi, register int ma)
1712 {
1713         register const char *cp;
1714         register int val;
1715         char *ep;
1716
1717         if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1718                 cp = str + 2;
1719                 val = (int)strtol(cp, &ep, 16);
1720         } else
1721                 val = (int)strtol(str, &ep, 10);
1722         if (*ep != '\0') {
1723                 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1724                     prog, str, what);
1725                 exit(1);
1726         }
1727         if (val < mi && mi >= 0) {
1728                 if (mi == 0)
1729                         Fprintf(stderr, "%s: %s must be >= %d\n",
1730                             prog, what, mi);
1731                 else
1732                         Fprintf(stderr, "%s: %s must be > %d\n",
1733                             prog, what, mi - 1);
1734                 exit(1);
1735         }
1736         if (val > ma && ma >= 0) {
1737                 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1738                 exit(1);
1739         }
1740         return (val);
1741 }
1742
1743 struct outproto *
1744 setproto(char *pname)
1745 {
1746         struct outproto *proto;
1747         int i;
1748
1749         for (i = 0; protos[i].name != NULL; i++) {
1750                 if (strcasecmp(protos[i].name, pname) == 0) {
1751                         break;
1752                 }
1753         }
1754         proto = &protos[i];
1755         if (proto->name == NULL) {      /* generic handler */
1756                 struct protoent *pe;
1757                 u_long pnum;
1758
1759                 /* Determine the IP protocol number */
1760                 if ((pe = getprotobyname(pname)) != NULL)
1761                         pnum = pe->p_proto;
1762                 else
1763                         pnum = str2val(optarg, "proto number", 1, 255);
1764                 proto->num = pnum;
1765         }
1766         return proto;
1767 }
1768
1769 void
1770 pkt_compare(const u_char *a, int la, const u_char *b, int lb) {
1771         int l;
1772         int i;
1773
1774         for (i = 0; i < la; i++)
1775                 Printf("%02x", (unsigned int)a[i]);
1776         Printf("\n");
1777         l = (la <= lb) ? la : lb;
1778         for (i = 0; i < l; i++)
1779                 if (a[i] == b[i])
1780                         Printf("__");
1781                 else
1782                         Printf("%02x", (unsigned int)b[i]);
1783         for (; i < lb; i++)
1784                 Printf("%02x", (unsigned int)b[i]);
1785         Printf("\n");
1786 }
1787
1788
1789 void
1790 usage(void)
1791 {
1792         extern char version[];
1793
1794         Fprintf(stderr, "Version %s\n", version);
1795         Fprintf(stderr,
1796             "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
1797             "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
1798             "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog);
1799         exit(1);
1800 }