xref: /minix3/usr.sbin/traceroute/traceroute.c (revision bb9622b5ed41bec48062bf9c6806832c8984f025)
17f5f010bSBen Gras /*	$NetBSD: traceroute.c,v 1.81 2012/08/16 00:40:28 zafer Exp $	*/
27f5f010bSBen Gras 
37f5f010bSBen Gras /*
47f5f010bSBen Gras  * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
57f5f010bSBen Gras  *	The Regents of the University of California.  All rights reserved.
67f5f010bSBen Gras  *
77f5f010bSBen Gras  * Redistribution and use in source and binary forms, with or without
87f5f010bSBen Gras  * modification, are permitted provided that: (1) source code distributions
97f5f010bSBen Gras  * retain the above copyright notice and this paragraph in its entirety, (2)
107f5f010bSBen Gras  * distributions including binary code include the above copyright notice and
117f5f010bSBen Gras  * this paragraph in its entirety in the documentation or other materials
127f5f010bSBen Gras  * provided with the distribution, and (3) all advertising materials mentioning
137f5f010bSBen Gras  * features or use of this software display the following acknowledgement:
147f5f010bSBen Gras  * ``This product includes software developed by the University of California,
157f5f010bSBen Gras  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
167f5f010bSBen Gras  * the University nor the names of its contributors may be used to endorse
177f5f010bSBen Gras  * or promote products derived from this software without specific prior
187f5f010bSBen Gras  * written permission.
197f5f010bSBen Gras  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
207f5f010bSBen Gras  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
217f5f010bSBen Gras  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
227f5f010bSBen Gras  */
237f5f010bSBen Gras 
247f5f010bSBen Gras #include <sys/cdefs.h>
257f5f010bSBen Gras #ifndef lint
267f5f010bSBen Gras #if 0
277f5f010bSBen Gras static const char rcsid[] =
287f5f010bSBen Gras     "@(#)Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp  (LBL)";
297f5f010bSBen Gras #else
307f5f010bSBen Gras __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997,\
317f5f010bSBen Gras  1998, 1999, 2000\
327f5f010bSBen Gras  The Regents of the University of California.  All rights reserved.");
337f5f010bSBen Gras __RCSID("$NetBSD: traceroute.c,v 1.81 2012/08/16 00:40:28 zafer Exp $");
347f5f010bSBen Gras #endif
357f5f010bSBen Gras #endif
367f5f010bSBen Gras 
377f5f010bSBen Gras /*
387f5f010bSBen Gras  * traceroute host  - trace the route ip packets follow going to "host".
397f5f010bSBen Gras  *
407f5f010bSBen Gras  * Attempt to trace the route an ip packet would follow to some
417f5f010bSBen Gras  * internet host.  We find out intermediate hops by launching probe
427f5f010bSBen Gras  * packets with a small ttl (time to live) then listening for an
437f5f010bSBen Gras  * icmp "time exceeded" reply from a gateway.  We start our probes
447f5f010bSBen Gras  * with a ttl of one and increase by one until we get an icmp "port
457f5f010bSBen Gras  * unreachable" (which means we got to "host") or hit a max (which
467f5f010bSBen Gras  * defaults to 30 hops & can be changed with the -m flag).  Three
477f5f010bSBen Gras  * probes (change with -q flag) are sent at each ttl setting and a
487f5f010bSBen Gras  * line is printed showing the ttl, address of the gateway and
497f5f010bSBen Gras  * round trip time of each probe.  If the probe answers come from
507f5f010bSBen Gras  * different gateways, the address of each responding system will
517f5f010bSBen Gras  * be printed.  If there is no response within a 5 sec. timeout
527f5f010bSBen Gras  * interval (changed with the -w flag), a "*" is printed for that
537f5f010bSBen Gras  * probe.
547f5f010bSBen Gras  *
557f5f010bSBen Gras  * Probe packets are UDP format.  We don't want the destination
567f5f010bSBen Gras  * host to process them so the destination port is set to an
577f5f010bSBen Gras  * unlikely value (if some clod on the destination is using that
587f5f010bSBen Gras  * value, it can be changed with the -p flag).
597f5f010bSBen Gras  *
607f5f010bSBen Gras  * A sample use might be:
617f5f010bSBen Gras  *
627f5f010bSBen Gras  *     [yak 71]% traceroute nis.nsf.net.
637f5f010bSBen Gras  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
647f5f010bSBen Gras  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
657f5f010bSBen Gras  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
667f5f010bSBen Gras  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
677f5f010bSBen Gras  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
687f5f010bSBen Gras  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
697f5f010bSBen Gras  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
707f5f010bSBen Gras  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
717f5f010bSBen Gras  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
727f5f010bSBen Gras  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
737f5f010bSBen Gras  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
747f5f010bSBen Gras  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
757f5f010bSBen Gras  *
767f5f010bSBen Gras  * Note that lines 2 & 3 are the same.  This is due to a buggy
777f5f010bSBen Gras  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
787f5f010bSBen Gras  * packets with a zero ttl.
797f5f010bSBen Gras  *
807f5f010bSBen Gras  * A more interesting example is:
817f5f010bSBen Gras  *
827f5f010bSBen Gras  *     [yak 72]% traceroute allspice.lcs.mit.edu.
837f5f010bSBen Gras  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
847f5f010bSBen Gras  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
857f5f010bSBen Gras  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
867f5f010bSBen Gras  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
877f5f010bSBen Gras  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
887f5f010bSBen Gras  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
897f5f010bSBen Gras  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
907f5f010bSBen Gras  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
917f5f010bSBen Gras  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
927f5f010bSBen Gras  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
937f5f010bSBen Gras  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
947f5f010bSBen Gras  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
957f5f010bSBen Gras  *     12  * * *
967f5f010bSBen Gras  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
977f5f010bSBen Gras  *     14  * * *
987f5f010bSBen Gras  *     15  * * *
997f5f010bSBen Gras  *     16  * * *
1007f5f010bSBen Gras  *     17  * * *
1017f5f010bSBen Gras  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
1027f5f010bSBen Gras  *
1037f5f010bSBen Gras  * (I start to see why I'm having so much trouble with mail to
1047f5f010bSBen Gras  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
1057f5f010bSBen Gras  * either don't send ICMP "time exceeded" messages or send them
1067f5f010bSBen Gras  * with a ttl too small to reach us.  14 - 17 are running the
1077f5f010bSBen Gras  * MIT C Gateway code that doesn't send "time exceeded"s.  God
1087f5f010bSBen Gras  * only knows what's going on with 12.
1097f5f010bSBen Gras  *
1107f5f010bSBen Gras  * The silent gateway 12 in the above may be the result of a bug in
1117f5f010bSBen Gras  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
1127f5f010bSBen Gras  * sends an unreachable message using whatever ttl remains in the
1137f5f010bSBen Gras  * original datagram.  Since, for gateways, the remaining ttl is
1147f5f010bSBen Gras  * zero, the icmp "time exceeded" is guaranteed to not make it back
1157f5f010bSBen Gras  * to us.  The behavior of this bug is slightly more interesting
1167f5f010bSBen Gras  * when it appears on the destination system:
1177f5f010bSBen Gras  *
1187f5f010bSBen Gras  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
1197f5f010bSBen Gras  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
1207f5f010bSBen Gras  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
1217f5f010bSBen Gras  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
1227f5f010bSBen Gras  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
1237f5f010bSBen Gras  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
1247f5f010bSBen Gras  *      7  * * *
1257f5f010bSBen Gras  *      8  * * *
1267f5f010bSBen Gras  *      9  * * *
1277f5f010bSBen Gras  *     10  * * *
1287f5f010bSBen Gras  *     11  * * *
1297f5f010bSBen Gras  *     12  * * *
1307f5f010bSBen Gras  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
1317f5f010bSBen Gras  *
1327f5f010bSBen Gras  * Notice that there are 12 "gateways" (13 is the final
1337f5f010bSBen Gras  * destination) and exactly the last half of them are "missing".
1347f5f010bSBen Gras  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
1357f5f010bSBen Gras  * is using the ttl from our arriving datagram as the ttl in its
1367f5f010bSBen Gras  * icmp reply.  So, the reply will time out on the return path
1377f5f010bSBen Gras  * (with no notice sent to anyone since icmp's aren't sent for
1387f5f010bSBen Gras  * icmp's) until we probe with a ttl that's at least twice the path
1397f5f010bSBen Gras  * length.  I.e., rip is really only 7 hops away.  A reply that
1407f5f010bSBen Gras  * returns with a ttl of 1 is a clue this problem exists.
1417f5f010bSBen Gras  * Traceroute prints a "!" after the time if the ttl is <= 1.
1427f5f010bSBen Gras  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
1437f5f010bSBen Gras  * non-standard (HPUX) software, expect to see this problem
1447f5f010bSBen Gras  * frequently and/or take care picking the target host of your
1457f5f010bSBen Gras  * probes.
1467f5f010bSBen Gras  *
1477f5f010bSBen Gras  * Other possible annotations after the time are !H, !N, !P (got a host,
1487f5f010bSBen Gras  * network or protocol unreachable, respectively), !S or !F (source
1497f5f010bSBen Gras  * route failed or fragmentation needed -- neither of these should
1507f5f010bSBen Gras  * ever occur and the associated gateway is busted if you see one).  If
1517f5f010bSBen Gras  * almost all the probes result in some kind of unreachable, traceroute
1527f5f010bSBen Gras  * will give up and exit.
1537f5f010bSBen Gras  *
1547f5f010bSBen Gras  * Notes
1557f5f010bSBen Gras  * -----
1567f5f010bSBen Gras  * This program must be run by root or be setuid.  (I suggest that
1577f5f010bSBen Gras  * you *don't* make it setuid -- casual use could result in a lot
1587f5f010bSBen Gras  * of unnecessary traffic on our poor, congested nets.)
1597f5f010bSBen Gras  *
1607f5f010bSBen Gras  * This program requires a kernel mod that does not appear in any
1617f5f010bSBen Gras  * system available from Berkeley:  A raw ip socket using proto
1627f5f010bSBen Gras  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
1637f5f010bSBen Gras  * opposed to data to be wrapped in a ip datagram).  See the README
1647f5f010bSBen Gras  * file that came with the source to this program for a description
1657f5f010bSBen Gras  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
1667f5f010bSBen Gras  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
1677f5f010bSBen Gras  * MODIFIED TO RUN THIS PROGRAM.
1687f5f010bSBen Gras  *
1697f5f010bSBen Gras  * The udp port usage may appear bizarre (well, ok, it is bizarre).
1707f5f010bSBen Gras  * The problem is that an icmp message only contains 8 bytes of
1717f5f010bSBen Gras  * data from the original datagram.  8 bytes is the size of a udp
1727f5f010bSBen Gras  * header so, if we want to associate replies with the original
1737f5f010bSBen Gras  * datagram, the necessary information must be encoded into the
1747f5f010bSBen Gras  * udp header (the ip id could be used but there's no way to
1757f5f010bSBen Gras  * interlock with the kernel's assignment of ip id's and, anyway,
1767f5f010bSBen Gras  * it would have taken a lot more kernel hacking to allow this
1777f5f010bSBen Gras  * code to set the ip id).  So, to allow two or more users to
1787f5f010bSBen Gras  * use traceroute simultaneously, we use this task's pid as the
1797f5f010bSBen Gras  * source port (the high bit is set to move the port number out
1807f5f010bSBen Gras  * of the "likely" range).  To keep track of which probe is being
1817f5f010bSBen Gras  * replied to (so times and/or hop counts don't get confused by a
1827f5f010bSBen Gras  * reply that was delayed in transit), we increment the destination
1837f5f010bSBen Gras  * port number before each probe.
1847f5f010bSBen Gras  *
1857f5f010bSBen Gras  * Don't use this as a coding example.  I was trying to find a
1867f5f010bSBen Gras  * routing problem and this code sort-of popped out after 48 hours
1877f5f010bSBen Gras  * without sleep.  I was amazed it ever compiled, much less ran.
1887f5f010bSBen Gras  *
1897f5f010bSBen Gras  * I stole the idea for this program from Steve Deering.  Since
1907f5f010bSBen Gras  * the first release, I've learned that had I attended the right
1917f5f010bSBen Gras  * IETF working group meetings, I also could have stolen it from Guy
1927f5f010bSBen Gras  * Almes or Matt Mathis.  I don't know (or care) who came up with
1937f5f010bSBen Gras  * the idea first.  I envy the originators' perspicacity and I'm
1947f5f010bSBen Gras  * glad they didn't keep the idea a secret.
1957f5f010bSBen Gras  *
1967f5f010bSBen Gras  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
1977f5f010bSBen Gras  * enhancements to the original distribution.
1987f5f010bSBen Gras  *
1997f5f010bSBen Gras  * I've hacked up a round-trip-route version of this that works by
2007f5f010bSBen Gras  * sending a loose-source-routed udp datagram through the destination
2017f5f010bSBen Gras  * back to yourself.  Unfortunately, SO many gateways botch source
2027f5f010bSBen Gras  * routing, the thing is almost worthless.  Maybe one day...
2037f5f010bSBen Gras  *
2047f5f010bSBen Gras  *  -- Van Jacobson (van@ee.lbl.gov)
2057f5f010bSBen Gras  *     Tue Dec 20 03:50:13 PST 1988
2067f5f010bSBen Gras  */
2077f5f010bSBen Gras 
2087f5f010bSBen Gras #include <sys/param.h>
2097f5f010bSBen Gras #include <sys/file.h>
2107f5f010bSBen Gras #include <sys/ioctl.h>
2117f5f010bSBen Gras #include <sys/socket.h>
2127f5f010bSBen Gras #include <sys/time.h>
2137f5f010bSBen Gras #include <sys/sysctl.h>
2147f5f010bSBen Gras 
2157f5f010bSBen Gras #include <netinet/in_systm.h>
2167f5f010bSBen Gras #include <netinet/in.h>
2177f5f010bSBen Gras #include <netinet/ip.h>
2187f5f010bSBen Gras #include <netinet/ip_var.h>
2197f5f010bSBen Gras #include <netinet/ip_icmp.h>
2207f5f010bSBen Gras #include <netinet/udp.h>
2217f5f010bSBen Gras #include <netinet/udp_var.h>
2227f5f010bSBen Gras 
2237f5f010bSBen Gras #include <arpa/inet.h>
2247f5f010bSBen Gras 
2257f5f010bSBen Gras #include <ctype.h>
2267f5f010bSBen Gras #include <err.h>
2277f5f010bSBen Gras #include <errno.h>
2287f5f010bSBen Gras #ifdef HAVE_MALLOC_H
2297f5f010bSBen Gras #include <malloc.h>
2307f5f010bSBen Gras #endif
2317f5f010bSBen Gras #include <memory.h>
2327f5f010bSBen Gras #include <netdb.h>
2337f5f010bSBen Gras #include <stdio.h>
2347f5f010bSBen Gras #include <stdlib.h>
2357f5f010bSBen Gras #include <string.h>
2367f5f010bSBen Gras #include <unistd.h>
2377f5f010bSBen Gras #include <poll.h>
2387f5f010bSBen Gras #ifdef IPSEC
2397f5f010bSBen Gras #include <net/route.h>
2407f5f010bSBen Gras #include <netipsec/ipsec.h>
2417f5f010bSBen Gras #endif
2427f5f010bSBen Gras 
2437f5f010bSBen Gras #include "gnuc.h"
2447f5f010bSBen Gras #ifdef HAVE_OS_PROTO_H
2457f5f010bSBen Gras #include "os-proto.h"
2467f5f010bSBen Gras #endif
2477f5f010bSBen Gras 
2487f5f010bSBen Gras /* rfc1716 */
2497f5f010bSBen Gras #ifndef ICMP_UNREACH_FILTER_PROHIB
2507f5f010bSBen Gras #define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
2517f5f010bSBen Gras #endif
2527f5f010bSBen Gras #ifndef ICMP_UNREACH_HOST_PRECEDENCE
2537f5f010bSBen Gras #define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
2547f5f010bSBen Gras #endif
2557f5f010bSBen Gras #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
2567f5f010bSBen Gras #define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
2577f5f010bSBen Gras #endif
2587f5f010bSBen Gras 
2597f5f010bSBen Gras #include "ifaddrlist.h"
2607f5f010bSBen Gras #include "as.h"
2617f5f010bSBen Gras #include "prog_ops.h"
2627f5f010bSBen Gras 
2637f5f010bSBen Gras /* Maximum number of gateways (include room for one noop) */
2647f5f010bSBen Gras #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
2657f5f010bSBen Gras 
2667f5f010bSBen Gras #ifndef MAXHOSTNAMELEN
2677f5f010bSBen Gras #define MAXHOSTNAMELEN	64
2687f5f010bSBen Gras #endif
2697f5f010bSBen Gras 
2707f5f010bSBen Gras #define Fprintf (void)fprintf
2717f5f010bSBen Gras #define Printf (void)printf
2727f5f010bSBen Gras 
2737f5f010bSBen Gras /* Host name and address list */
2747f5f010bSBen Gras struct hostinfo {
2757f5f010bSBen Gras 	char *name;
2767f5f010bSBen Gras 	int n;
2777f5f010bSBen Gras 	u_int32_t *addrs;
2787f5f010bSBen Gras };
2797f5f010bSBen Gras 
2807f5f010bSBen Gras /* Data section of the probe packet */
2817f5f010bSBen Gras struct outdata {
2827f5f010bSBen Gras 	u_char seq;		/* sequence number of this packet */
2837f5f010bSBen Gras 	u_char ttl;		/* ttl packet left with */
2847f5f010bSBen Gras 	struct tv32 {
2857f5f010bSBen Gras 		int32_t tv32_sec;
2867f5f010bSBen Gras 		int32_t tv32_usec;
2877f5f010bSBen Gras 	} tv;			/* time packet left */
2887f5f010bSBen Gras };
2897f5f010bSBen Gras 
2907f5f010bSBen Gras /*
2917f5f010bSBen Gras  * Support for ICMP extensions
2927f5f010bSBen Gras  *
2937f5f010bSBen Gras  * http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt
2947f5f010bSBen Gras  */
2957f5f010bSBen Gras #define ICMP_EXT_OFFSET    8 /* ICMP type, code, checksum, unused */ + \
2967f5f010bSBen Gras                          128 /* original datagram */
2977f5f010bSBen Gras #define ICMP_EXT_VERSION 2
2987f5f010bSBen Gras /*
2997f5f010bSBen Gras  * ICMP extensions, common header
3007f5f010bSBen Gras  */
3017f5f010bSBen Gras struct icmp_ext_cmn_hdr {
3027f5f010bSBen Gras #if BYTE_ORDER == BIG_ENDIAN
3037f5f010bSBen Gras 	unsigned char   version:4;
3047f5f010bSBen Gras 	unsigned char   reserved1:4;
3057f5f010bSBen Gras #else
3067f5f010bSBen Gras 	unsigned char   reserved1:4;
3077f5f010bSBen Gras 	unsigned char   version:4;
3087f5f010bSBen Gras #endif
3097f5f010bSBen Gras 	unsigned char   reserved2;
3107f5f010bSBen Gras 	unsigned short  checksum;
3117f5f010bSBen Gras };
3127f5f010bSBen Gras 
3137f5f010bSBen Gras /*
3147f5f010bSBen Gras  * ICMP extensions, object header
3157f5f010bSBen Gras  */
3167f5f010bSBen Gras struct icmp_ext_obj_hdr {
3177f5f010bSBen Gras     u_short length;
3187f5f010bSBen Gras     u_char  class_num;
3197f5f010bSBen Gras #define MPLS_STACK_ENTRY_CLASS 1
3207f5f010bSBen Gras     u_char  c_type;
3217f5f010bSBen Gras #define MPLS_STACK_ENTRY_C_TYPE 1
3227f5f010bSBen Gras };
3237f5f010bSBen Gras 
3247f5f010bSBen Gras struct mpls_header {
3257f5f010bSBen Gras #if BYTE_ORDER == BIG_ENDIAN
3267f5f010bSBen Gras 	 uint32_t	label:20;
3277f5f010bSBen Gras 	 unsigned char  exp:3;
3287f5f010bSBen Gras 	 unsigned char  s:1;
3297f5f010bSBen Gras 	 unsigned char  ttl:8;
3307f5f010bSBen Gras #else
3317f5f010bSBen Gras 	 unsigned char  ttl:8;
3327f5f010bSBen Gras 	 unsigned char  s:1;
3337f5f010bSBen Gras 	 unsigned char  exp:3;
3347f5f010bSBen Gras 	 uint32_t	label:20;
3357f5f010bSBen Gras #endif
3367f5f010bSBen Gras };
3377f5f010bSBen Gras 
3387f5f010bSBen Gras #ifndef HAVE_ICMP_NEXTMTU
3397f5f010bSBen Gras /* Path MTU Discovery (RFC1191) */
3407f5f010bSBen Gras struct my_pmtu {
3417f5f010bSBen Gras 	u_short ipm_void;
3427f5f010bSBen Gras 	u_short ipm_nextmtu;
3437f5f010bSBen Gras };
3447f5f010bSBen Gras #endif
3457f5f010bSBen Gras 
3467f5f010bSBen Gras static u_char	packet[512];		/* last inbound (icmp) packet */
3477f5f010bSBen Gras 
3487f5f010bSBen Gras static struct ip *outip;		/* last output (udp) packet */
3497f5f010bSBen Gras static struct udphdr *outudp;		/* last output (udp) packet */
3507f5f010bSBen Gras static void *outmark;			/* packed location of struct outdata */
3517f5f010bSBen Gras static struct outdata outsetup;	/* setup and copy for alignment */
3527f5f010bSBen Gras 
3537f5f010bSBen Gras static struct icmp *outicmp;		/* last output (icmp) packet */
3547f5f010bSBen Gras 
3557f5f010bSBen Gras /* loose source route gateway list (including room for final destination) */
3567f5f010bSBen Gras static u_int32_t gwlist[NGATEWAYS + 1];
3577f5f010bSBen Gras 
3587f5f010bSBen Gras static int s;				/* receive (icmp) socket file descriptor */
3597f5f010bSBen Gras static int sndsock;			/* send (udp/icmp) socket file descriptor */
3607f5f010bSBen Gras 
3617f5f010bSBen Gras static struct sockaddr whereto;		/* Who to try to reach */
3627f5f010bSBen Gras static struct sockaddr wherefrom;	/* Who we are */
3637f5f010bSBen Gras static int packlen;			/* total length of packet */
3647f5f010bSBen Gras static int minpacket;			/* min ip packet size */
3657f5f010bSBen Gras static int maxpacket = 32 * 1024;	/* max ip packet size */
3667f5f010bSBen Gras static int printed_ttl = 0;
3677f5f010bSBen Gras static int pmtu;			/* Path MTU Discovery (RFC1191) */
3687f5f010bSBen Gras static u_int pausemsecs;
3697f5f010bSBen Gras 
3707f5f010bSBen Gras static const char *prog;
3717f5f010bSBen Gras static char *source;
3727f5f010bSBen Gras static char *hostname;
3737f5f010bSBen Gras static char *device;
3747f5f010bSBen Gras #ifdef notdef
3757f5f010bSBen Gras static const char devnull[] = "/dev/null";
3767f5f010bSBen Gras #endif
3777f5f010bSBen Gras 
3787f5f010bSBen Gras static int nprobes = 3;
3797f5f010bSBen Gras static int max_ttl = 30;
3807f5f010bSBen Gras static int first_ttl = 1;
3817f5f010bSBen Gras static u_int16_t ident;
3827f5f010bSBen Gras static in_port_t port = 32768 + 666;	/* start udp dest port # for probe packets */
3837f5f010bSBen Gras 
3847f5f010bSBen Gras static int options;			/* socket options */
3857f5f010bSBen Gras static int verbose;
3867f5f010bSBen Gras static int waittime = 5;		/* time to wait for response (in seconds) */
3877f5f010bSBen Gras static int nflag;			/* print addresses numerically */
3887f5f010bSBen Gras static int dump;
3897f5f010bSBen Gras static int Mflag;			/* show MPLS labels if any */
3907f5f010bSBen Gras static int as_path;			/* print as numbers for each hop */
3917f5f010bSBen Gras static char *as_server = NULL;
3927f5f010bSBen Gras static void *asn;
3937f5f010bSBen Gras static int useicmp = 0;		/* use icmp echo instead of udp packets */
3947f5f010bSBen Gras #ifdef CANT_HACK_CKSUM
3957f5f010bSBen Gras static int doipcksum = 0;		/* don't calculate checksums */
3967f5f010bSBen Gras #else
3977f5f010bSBen Gras static int doipcksum = 1;		/* calculate checksums */
3987f5f010bSBen Gras #endif
3997f5f010bSBen Gras static int optlen;			/* length of ip options */
4007f5f010bSBen Gras 
4017f5f010bSBen Gras static int mtus[] = {
4027f5f010bSBen Gras         17914,
4037f5f010bSBen Gras          8166,
4047f5f010bSBen Gras          4464,
4057f5f010bSBen Gras          4352,
4067f5f010bSBen Gras          2048,
4077f5f010bSBen Gras          2002,
4087f5f010bSBen Gras          1536,
4097f5f010bSBen Gras          1500,
4107f5f010bSBen Gras          1492,
4117f5f010bSBen Gras          1480,
4127f5f010bSBen Gras          1280,
4137f5f010bSBen Gras          1006,
4147f5f010bSBen Gras           576,
4157f5f010bSBen Gras           552,
4167f5f010bSBen Gras           544,
4177f5f010bSBen Gras           512,
4187f5f010bSBen Gras           508,
4197f5f010bSBen Gras           296,
4207f5f010bSBen Gras            68,
4217f5f010bSBen Gras             0
4227f5f010bSBen Gras };
4237f5f010bSBen Gras static int *mtuptr = &mtus[0];
4247f5f010bSBen Gras static int mtudisc = 0;
4257f5f010bSBen Gras static int nextmtu;   /* from ICMP error, set by packet_ok(), might be 0 */
4267f5f010bSBen Gras 
4277f5f010bSBen Gras /* Forwards */
4287f5f010bSBen Gras static double deltaT(struct timeval *, struct timeval *);
4297f5f010bSBen Gras static void freehostinfo(struct hostinfo *);
4307f5f010bSBen Gras static void getaddr(u_int32_t *, char *);
4317f5f010bSBen Gras static struct hostinfo *gethostinfo(char *);
4327f5f010bSBen Gras static u_int16_t in_cksum(u_int16_t *, int);
4337f5f010bSBen Gras static u_int16_t in_cksum2(u_int16_t, u_int16_t *, int);
4347f5f010bSBen Gras static char *inetname(struct in_addr);
4357f5f010bSBen Gras static int packet_ok(u_char *, ssize_t, struct sockaddr_in *, int);
4367f5f010bSBen Gras static const char *pr_type(u_char);
4377f5f010bSBen Gras static void print(u_char *, int, struct sockaddr_in *);
4387f5f010bSBen Gras static void resize_packet(void);
4397f5f010bSBen Gras static void dump_packet(void);
4407f5f010bSBen Gras static void send_probe(int, int, struct timeval *);
4417f5f010bSBen Gras static void setsin(struct sockaddr_in *, u_int32_t);
4427f5f010bSBen Gras static int str2val(const char *, const char *, int, int);
4437f5f010bSBen Gras static void tvsub(struct timeval *, struct timeval *);
4447f5f010bSBen Gras static void usage(void) __attribute__((__noreturn__));
4457f5f010bSBen Gras static ssize_t wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
4467f5f010bSBen Gras static void decode_extensions(unsigned char *buf, int ip_len);
4477f5f010bSBen Gras static void frag_err(void);
4487f5f010bSBen Gras static int find_local_ip(struct sockaddr_in *, struct sockaddr_in *);
4497f5f010bSBen Gras #ifdef IPSEC
4507f5f010bSBen Gras #ifdef IPSEC_POLICY_IPSEC
4517f5f010bSBen Gras static int setpolicy(int, const char *);
4527f5f010bSBen Gras #endif
4537f5f010bSBen Gras #endif
4547f5f010bSBen Gras 
4557f5f010bSBen Gras int
main(int argc,char ** argv)4567f5f010bSBen Gras main(int argc, char **argv)
4577f5f010bSBen Gras {
4587f5f010bSBen Gras 	int op, code, n;
4597f5f010bSBen Gras 	u_char *outp;
4607f5f010bSBen Gras 	u_int32_t *ap;
4617f5f010bSBen Gras 	struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
4627f5f010bSBen Gras 	struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
4637f5f010bSBen Gras 	struct hostinfo *hi;
4647f5f010bSBen Gras 	int on = 1;
4657f5f010bSBen Gras 	int ttl, probe, i;
4667f5f010bSBen Gras 	int seq = 0;
4677f5f010bSBen Gras 	int tos = 0, settos = 0, ttl_flag = 0;
4687f5f010bSBen Gras 	int lsrr = 0;
4697f5f010bSBen Gras 	u_int16_t off = 0;
4707f5f010bSBen Gras 	struct ifaddrlist *al, *al2;
4717f5f010bSBen Gras 	char errbuf[132];
4727f5f010bSBen Gras 	int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
4737f5f010bSBen Gras 	size_t size = sizeof(max_ttl);
4747f5f010bSBen Gras 
4757f5f010bSBen Gras 	setprogname(argv[0]);
4767f5f010bSBen Gras 	prog = getprogname();
4777f5f010bSBen Gras 
4787f5f010bSBen Gras 	if (prog_init && prog_init() == -1)
4797f5f010bSBen Gras 		err(1, "init failed");
4807f5f010bSBen Gras 
4817f5f010bSBen Gras #ifdef notdef
4827f5f010bSBen Gras 	/* Kernel takes care of it */
4837f5f010bSBen Gras 	/* Insure the socket fds won't be 0, 1 or 2 */
4847f5f010bSBen Gras 	if (open(devnull, O_RDONLY) < 0 ||
4857f5f010bSBen Gras 	    open(devnull, O_RDONLY) < 0 ||
4867f5f010bSBen Gras 	    open(devnull, O_RDONLY) < 0)
4877f5f010bSBen Gras 		err(1, "Cannot open `%s'", devnull);
4887f5f010bSBen Gras #endif
4897f5f010bSBen Gras 	if ((s = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
4907f5f010bSBen Gras 		err(1, "icmp socket");
4917f5f010bSBen Gras 
4927f5f010bSBen Gras 	/*
4937f5f010bSBen Gras 	 * XXX 'useicmp' will always be zero here. I think the HP-UX users
4947f5f010bSBen Gras 	 * running our traceroute code will forgive us.
4957f5f010bSBen Gras 	 */
4967f5f010bSBen Gras #ifndef __hpux
4977f5f010bSBen Gras 	sndsock = prog_socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
4987f5f010bSBen Gras #else
4997f5f010bSBen Gras 	sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW
5007f5f010bSBen Gras 	    useicmp ? IPPROTO_ICMP : IPPROTO_UDP);
5017f5f010bSBen Gras #endif
5027f5f010bSBen Gras 	if (sndsock < 0)
5037f5f010bSBen Gras 		err(1, "raw socket");
5047f5f010bSBen Gras 
5057f5f010bSBen Gras 	(void) prog_sysctl(mib, sizeof(mib)/sizeof(mib[0]), &max_ttl, &size,
5067f5f010bSBen Gras 	    NULL, 0);
5077f5f010bSBen Gras 
5087f5f010bSBen Gras 	opterr = 0;
5097f5f010bSBen Gras 	while ((op = getopt(argc, argv, "aA:dDFPIMnlrvxf:g:i:m:p:q:s:t:w:z:")) != -1)
5107f5f010bSBen Gras 		switch (op) {
5117f5f010bSBen Gras 
5127f5f010bSBen Gras 		case 'a':
5137f5f010bSBen Gras 			as_path = 1;
5147f5f010bSBen Gras 			break;
5157f5f010bSBen Gras 
5167f5f010bSBen Gras 		case 'A':
5177f5f010bSBen Gras 			as_path = 1;
5187f5f010bSBen Gras 			as_server = optarg;
5197f5f010bSBen Gras 			break;
5207f5f010bSBen Gras 
5217f5f010bSBen Gras 		case 'd':
5227f5f010bSBen Gras 			options |= SO_DEBUG;
5237f5f010bSBen Gras 			break;
5247f5f010bSBen Gras 
5257f5f010bSBen Gras 		case 'D':
5267f5f010bSBen Gras 			dump = 1;
5277f5f010bSBen Gras 			break;
5287f5f010bSBen Gras 
5297f5f010bSBen Gras 		case 'f':
5307f5f010bSBen Gras 			first_ttl = str2val(optarg, "first ttl", 1, 255);
5317f5f010bSBen Gras 			break;
5327f5f010bSBen Gras 
5337f5f010bSBen Gras 		case 'F':
5347f5f010bSBen Gras 			off = IP_DF;
5357f5f010bSBen Gras 			break;
5367f5f010bSBen Gras 
5377f5f010bSBen Gras 		case 'g':
5387f5f010bSBen Gras 			if (lsrr >= NGATEWAYS)
5397f5f010bSBen Gras 				errx(1, "more than %d gateways", NGATEWAYS);
5407f5f010bSBen Gras 			getaddr(gwlist + lsrr, optarg);
5417f5f010bSBen Gras 			++lsrr;
5427f5f010bSBen Gras 			break;
5437f5f010bSBen Gras 
5447f5f010bSBen Gras 		case 'i':
5457f5f010bSBen Gras 			device = optarg;
5467f5f010bSBen Gras 			break;
5477f5f010bSBen Gras 
5487f5f010bSBen Gras 		case 'I':
5497f5f010bSBen Gras 			++useicmp;
5507f5f010bSBen Gras 			break;
5517f5f010bSBen Gras 
5527f5f010bSBen Gras 		case 'l':
5537f5f010bSBen Gras 			++ttl_flag;
5547f5f010bSBen Gras 			break;
5557f5f010bSBen Gras 
5567f5f010bSBen Gras 		case 'm':
5577f5f010bSBen Gras 			max_ttl = str2val(optarg, "max ttl", 1, 255);
5587f5f010bSBen Gras 			break;
5597f5f010bSBen Gras 
5607f5f010bSBen Gras 		case 'M':
5617f5f010bSBen Gras 			Mflag = 1;
5627f5f010bSBen Gras 			break;
5637f5f010bSBen Gras 
5647f5f010bSBen Gras 		case 'n':
5657f5f010bSBen Gras 			++nflag;
5667f5f010bSBen Gras 			break;
5677f5f010bSBen Gras 
5687f5f010bSBen Gras 		case 'p':
5697f5f010bSBen Gras 			port = (u_short)str2val(optarg, "port",
5707f5f010bSBen Gras 			    1, (1 << 16) - 1);
5717f5f010bSBen Gras 			break;
5727f5f010bSBen Gras 
5737f5f010bSBen Gras 		case 'q':
5747f5f010bSBen Gras 			nprobes = str2val(optarg, "nprobes", 1, -1);
5757f5f010bSBen Gras 			break;
5767f5f010bSBen Gras 
5777f5f010bSBen Gras 		case 'r':
5787f5f010bSBen Gras 			options |= SO_DONTROUTE;
5797f5f010bSBen Gras 			break;
5807f5f010bSBen Gras 
5817f5f010bSBen Gras 		case 's':
5827f5f010bSBen Gras 			/*
5837f5f010bSBen Gras 			 * set the ip source address of the outbound
5847f5f010bSBen Gras 			 * probe (e.g., on a multi-homed host).
5857f5f010bSBen Gras 			 */
5867f5f010bSBen Gras 			source = optarg;
5877f5f010bSBen Gras 			break;
5887f5f010bSBen Gras 
5897f5f010bSBen Gras 		case 't':
5907f5f010bSBen Gras 			tos = str2val(optarg, "tos", 0, 255);
5917f5f010bSBen Gras 			++settos;
5927f5f010bSBen Gras 			break;
5937f5f010bSBen Gras 
5947f5f010bSBen Gras 		case 'v':
5957f5f010bSBen Gras 			++verbose;
5967f5f010bSBen Gras 			break;
5977f5f010bSBen Gras 
5987f5f010bSBen Gras 		case 'x':
5997f5f010bSBen Gras 			doipcksum = (doipcksum == 0);
6007f5f010bSBen Gras 			break;
6017f5f010bSBen Gras 
6027f5f010bSBen Gras 		case 'w':
6037f5f010bSBen Gras 			waittime = str2val(optarg, "wait time",
6047f5f010bSBen Gras 			    2, 24 * 60 * 60);
6057f5f010bSBen Gras 			break;
6067f5f010bSBen Gras 
6077f5f010bSBen Gras 		case 'z':
6087f5f010bSBen Gras 			pausemsecs = str2val(optarg, "pause msecs",
6097f5f010bSBen Gras 			    0, 60 * 60 * 1000);
6107f5f010bSBen Gras 
6117f5f010bSBen Gras 		case 'P':
6127f5f010bSBen Gras 			off = IP_DF;
6137f5f010bSBen Gras 			mtudisc = 1;
6147f5f010bSBen Gras 			break;
6157f5f010bSBen Gras 
6167f5f010bSBen Gras 		default:
6177f5f010bSBen Gras 			usage();
6187f5f010bSBen Gras 		}
6197f5f010bSBen Gras 
6207f5f010bSBen Gras 	if (first_ttl > max_ttl)
6217f5f010bSBen Gras 		errx(1, "first ttl (%d) may not be greater than max ttl (%d)",
6227f5f010bSBen Gras 		    first_ttl, max_ttl);
6237f5f010bSBen Gras 
6247f5f010bSBen Gras 	if (!doipcksum)
6257f5f010bSBen Gras 		warnx("ip checksums disabled");
6267f5f010bSBen Gras 
6277f5f010bSBen Gras 	if (lsrr > 0)
6287f5f010bSBen Gras 		optlen = (lsrr + 1) * sizeof(gwlist[0]);
6297f5f010bSBen Gras 	minpacket = sizeof(*outip) + sizeof(struct outdata) + optlen;
6307f5f010bSBen Gras 	if (useicmp)
6317f5f010bSBen Gras 		minpacket += 8;			/* XXX magic number */
6327f5f010bSBen Gras 	else
6337f5f010bSBen Gras 		minpacket += sizeof(*outudp);
6347f5f010bSBen Gras 	packlen = minpacket;		/* minimum sized packet */
6357f5f010bSBen Gras 
6367f5f010bSBen Gras 	if (mtudisc)
6377f5f010bSBen Gras 		packlen = *mtuptr++;
6387f5f010bSBen Gras 
6397f5f010bSBen Gras 	/* Process destination and optional packet size */
6407f5f010bSBen Gras 	switch (argc - optind) {
6417f5f010bSBen Gras 
6427f5f010bSBen Gras 	case 2:
6437f5f010bSBen Gras 		packlen = str2val(argv[optind + 1],
6447f5f010bSBen Gras 		    "packet length", minpacket, maxpacket);
6457f5f010bSBen Gras 		/* Fall through */
6467f5f010bSBen Gras 
6477f5f010bSBen Gras 	case 1:
6487f5f010bSBen Gras 		hostname = argv[optind];
6497f5f010bSBen Gras 		hi = gethostinfo(hostname);
6507f5f010bSBen Gras 		setsin(to, hi->addrs[0]);
6517f5f010bSBen Gras 		if (hi->n > 1)
6527f5f010bSBen Gras 			warnx("%s has multiple addresses; using %s",
6537f5f010bSBen Gras 			    hostname, inet_ntoa(to->sin_addr));
6547f5f010bSBen Gras 		hostname = hi->name;
6557f5f010bSBen Gras 		hi->name = NULL;
6567f5f010bSBen Gras 		freehostinfo(hi);
6577f5f010bSBen Gras 		break;
6587f5f010bSBen Gras 
6597f5f010bSBen Gras 	default:
6607f5f010bSBen Gras 		usage();
6617f5f010bSBen Gras 	}
6627f5f010bSBen Gras 
6637f5f010bSBen Gras #ifdef HAVE_SETLINEBUF
6647f5f010bSBen Gras 	setlinebuf (stdout);
6657f5f010bSBen Gras #else
6667f5f010bSBen Gras 	setvbuf(stdout, NULL, _IOLBF, 0);
6677f5f010bSBen Gras #endif
6687f5f010bSBen Gras 
6697f5f010bSBen Gras 	outip = malloc((unsigned)packlen);
6707f5f010bSBen Gras 	if (outip == NULL)
6717f5f010bSBen Gras 		err(1, "malloc");
6727f5f010bSBen Gras 	memset(outip, 0, packlen);
6737f5f010bSBen Gras 
6747f5f010bSBen Gras 	outip->ip_v = IPVERSION;
6757f5f010bSBen Gras 	if (settos)
6767f5f010bSBen Gras 		outip->ip_tos = tos;
6777f5f010bSBen Gras #ifdef BYTESWAP_IP_HDR
6787f5f010bSBen Gras 	outip->ip_len = htons(packlen);
6797f5f010bSBen Gras 	outip->ip_off = htons(off);
6807f5f010bSBen Gras #else
6817f5f010bSBen Gras 	outip->ip_len = packlen;
6827f5f010bSBen Gras 	outip->ip_off = off;
6837f5f010bSBen Gras #endif
6847f5f010bSBen Gras 	outp = (u_char *)(outip + 1);
6857f5f010bSBen Gras #ifdef HAVE_RAW_OPTIONS
6867f5f010bSBen Gras 	if (lsrr > 0) {
6877f5f010bSBen Gras 		u_char *optlist;
6887f5f010bSBen Gras 
6897f5f010bSBen Gras 		optlist = outp;
6907f5f010bSBen Gras 		outp += optlen;
6917f5f010bSBen Gras 
6927f5f010bSBen Gras 		/* final hop */
6937f5f010bSBen Gras 		gwlist[lsrr] = to->sin_addr.s_addr;
6947f5f010bSBen Gras 
6957f5f010bSBen Gras 		outip->ip_dst.s_addr = gwlist[0];
6967f5f010bSBen Gras 
6977f5f010bSBen Gras 		/* force 4 byte alignment */
6987f5f010bSBen Gras 		optlist[0] = IPOPT_NOP;
6997f5f010bSBen Gras 		/* loose source route option */
7007f5f010bSBen Gras 		optlist[1] = IPOPT_LSRR;
7017f5f010bSBen Gras 		i = lsrr * sizeof(gwlist[0]);
7027f5f010bSBen Gras 		optlist[2] = i + 3;
7037f5f010bSBen Gras 		/* Pointer to LSRR addresses */
7047f5f010bSBen Gras 		optlist[3] = IPOPT_MINOFF;
7057f5f010bSBen Gras 		memcpy(optlist + 4, gwlist + 1, i);
7067f5f010bSBen Gras 	} else
7077f5f010bSBen Gras #endif
7087f5f010bSBen Gras 		outip->ip_dst = to->sin_addr;
7097f5f010bSBen Gras 
7107f5f010bSBen Gras 	outip->ip_hl = (outp - (u_char *)outip) >> 2;
7117f5f010bSBen Gras 	ident = htons(arc4random() & 0xffff) | 0x8000;
7127f5f010bSBen Gras 	if (useicmp) {
7137f5f010bSBen Gras 		outip->ip_p = IPPROTO_ICMP;
7147f5f010bSBen Gras 
7157f5f010bSBen Gras 		outicmp = (struct icmp *)outp;
7167f5f010bSBen Gras 		outicmp->icmp_type = ICMP_ECHO;
7177f5f010bSBen Gras 		outicmp->icmp_id = htons(ident);
7187f5f010bSBen Gras 
7197f5f010bSBen Gras 		outmark = outp + 8;	/* XXX magic number */
7207f5f010bSBen Gras 	} else {
7217f5f010bSBen Gras 		outip->ip_p = IPPROTO_UDP;
7227f5f010bSBen Gras 
7237f5f010bSBen Gras 		outudp = (struct udphdr *)outp;
7247f5f010bSBen Gras 		outudp->uh_sport = htons(ident);
7257f5f010bSBen Gras 		outudp->uh_ulen =
7267f5f010bSBen Gras 		    htons((u_int16_t)(packlen - (sizeof(*outip) + optlen)));
7277f5f010bSBen Gras 		outmark = outudp + 1;
7287f5f010bSBen Gras 	}
7297f5f010bSBen Gras 
7307f5f010bSBen Gras 	if (options & SO_DEBUG)
7317f5f010bSBen Gras 		(void)prog_setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
7327f5f010bSBen Gras 		    sizeof(on));
7337f5f010bSBen Gras #ifdef IPSEC
7347f5f010bSBen Gras #ifdef IPSEC_POLICY_IPSEC
7357f5f010bSBen Gras 	/*
7367f5f010bSBen Gras 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7377f5f010bSBen Gras 	 * turned off.
7387f5f010bSBen Gras 	 */
7397f5f010bSBen Gras 	if (setpolicy(s, "in bypass") < 0)
7407f5f010bSBen Gras 		exit(1);
7417f5f010bSBen Gras 	if (setpolicy(s, "out bypass") < 0)
7427f5f010bSBen Gras 		exit(1);
7437f5f010bSBen Gras #else
7447f5f010bSBen Gras     {
7457f5f010bSBen Gras 	int level = IPSEC_LEVEL_AVAIL;
7467f5f010bSBen Gras 
7477f5f010bSBen Gras 	(void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &level,
7487f5f010bSBen Gras 		sizeof(level));
7497f5f010bSBen Gras 	(void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, &level,
7507f5f010bSBen Gras 		sizeof(level));
7517f5f010bSBen Gras #ifdef IP_AUTH_TRANS_LEVEL
7527f5f010bSBen Gras 	(void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &level,
7537f5f010bSBen Gras 		sizeof(level));
7547f5f010bSBen Gras #else
7557f5f010bSBen Gras 	(void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_LEVEL, &level,
7567f5f010bSBen Gras 		sizeof(level));
7577f5f010bSBen Gras #endif
7587f5f010bSBen Gras #ifdef IP_AUTH_NETWORK_LEVEL
7597f5f010bSBen Gras 	(void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_NETWORK_LEVEL, &level,
7607f5f010bSBen Gras 		sizeof(level));
7617f5f010bSBen Gras #endif
7627f5f010bSBen Gras     }
7637f5f010bSBen Gras #endif /*IPSEC_POLICY_IPSEC*/
7647f5f010bSBen Gras #endif /*IPSEC*/
7657f5f010bSBen Gras 
7667f5f010bSBen Gras #ifdef IPSEC
7677f5f010bSBen Gras #ifdef IPSEC_POLICY_IPSEC
7687f5f010bSBen Gras 	/*
7697f5f010bSBen Gras 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7707f5f010bSBen Gras 	 * turned off.
7717f5f010bSBen Gras 	 */
7727f5f010bSBen Gras 	if (setpolicy(sndsock, "in bypass") < 0)
7737f5f010bSBen Gras 		exit(1);
7747f5f010bSBen Gras 	if (setpolicy(sndsock, "out bypass") < 0)
7757f5f010bSBen Gras 		exit(1);
7767f5f010bSBen Gras #else
7777f5f010bSBen Gras     {
7787f5f010bSBen Gras 	int level = IPSEC_LEVEL_BYPASS;
7797f5f010bSBen Gras 
7807f5f010bSBen Gras 	(void)prog_setsockopt(sndsock, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &level,
7817f5f010bSBen Gras 		sizeof(level));
7827f5f010bSBen Gras 	(void)prog_setsockopt(sndsock, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, &level,
7837f5f010bSBen Gras 		sizeof(level));
7847f5f010bSBen Gras #ifdef IP_AUTH_TRANS_LEVEL
7857f5f010bSBen Gras 	(void)prog_setsockopt(sndsock, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &level,
7867f5f010bSBen Gras 		sizeof(level));
7877f5f010bSBen Gras #else
7887f5f010bSBen Gras 	(void)prog_setsockopt(sndsock, IPPROTO_IP, IP_AUTH_LEVEL, &level,
7897f5f010bSBen Gras 		sizeof(level));
7907f5f010bSBen Gras #endif
7917f5f010bSBen Gras #ifdef IP_AUTH_NETWORK_LEVEL
7927f5f010bSBen Gras 	(void)prog_setsockopt(sndsock, IPPROTO_IP, IP_AUTH_NETWORK_LEVEL, &level,
7937f5f010bSBen Gras 		sizeof(level));
7947f5f010bSBen Gras #endif
7957f5f010bSBen Gras     }
7967f5f010bSBen Gras #endif /*IPSEC_POLICY_IPSEC*/
7977f5f010bSBen Gras #endif /*IPSEC*/
7987f5f010bSBen Gras 
7997f5f010bSBen Gras #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
8007f5f010bSBen Gras 	if (lsrr > 0) {
8017f5f010bSBen Gras 		u_char optlist[MAX_IPOPTLEN];
8027f5f010bSBen Gras 
8037f5f010bSBen Gras 		/* final hop */
8047f5f010bSBen Gras 		gwlist[lsrr] = to->sin_addr.s_addr;
8057f5f010bSBen Gras 		++lsrr;
8067f5f010bSBen Gras 
8077f5f010bSBen Gras 		/* force 4 byte alignment */
8087f5f010bSBen Gras 		optlist[0] = IPOPT_NOP;
8097f5f010bSBen Gras 		/* loose source route option */
8107f5f010bSBen Gras 		optlist[1] = IPOPT_LSRR;
8117f5f010bSBen Gras 		i = lsrr * sizeof(gwlist[0]);
8127f5f010bSBen Gras 		optlist[2] = i + 3;
8137f5f010bSBen Gras 		/* Pointer to LSRR addresses */
8147f5f010bSBen Gras 		optlist[3] = IPOPT_MINOFF;
8157f5f010bSBen Gras 		memcpy(optlist + 4, gwlist, i);
8167f5f010bSBen Gras 
8177f5f010bSBen Gras 		if ((prog_setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, optlist,
8187f5f010bSBen Gras 		    i + sizeof(gwlist[0]))) < 0)
8197f5f010bSBen Gras 			err(1, "IP_OPTIONS");
8207f5f010bSBen Gras 	}
8217f5f010bSBen Gras #endif
8227f5f010bSBen Gras 
8237f5f010bSBen Gras #ifdef SO_SNDBUF
8247f5f010bSBen Gras 	if (prog_setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
8257f5f010bSBen Gras 	    sizeof(packlen)) < 0)
8267f5f010bSBen Gras 		err(1, "SO_SNDBUF");
8277f5f010bSBen Gras #endif
8287f5f010bSBen Gras #ifdef IP_HDRINCL
8297f5f010bSBen Gras 	if (prog_setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
8307f5f010bSBen Gras 	    sizeof(on)) < 0)
8317f5f010bSBen Gras 		err(1, "IP_HDRINCL");
8327f5f010bSBen Gras #else
8337f5f010bSBen Gras #ifdef IP_TOS
8347f5f010bSBen Gras 	if (settos && prog_setsockopt(sndsock, IPPROTO_IP, IP_TOS,
8357f5f010bSBen Gras 	    &tos, sizeof(tos)) < 0)
8367f5f010bSBen Gras 		err(1, "setsockopt tos %d", tos);
8377f5f010bSBen Gras #endif
8387f5f010bSBen Gras #endif
8397f5f010bSBen Gras 	if (options & SO_DEBUG)
8407f5f010bSBen Gras 		if (prog_setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, &on,
8417f5f010bSBen Gras 		    sizeof(on)) < 0)
8427f5f010bSBen Gras 			err(1, "setsockopt debug %d", tos);
8437f5f010bSBen Gras 	if (options & SO_DONTROUTE)
8447f5f010bSBen Gras 		if (prog_setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, &on,
8457f5f010bSBen Gras 		    sizeof(on)) < 0)
8467f5f010bSBen Gras 			err(1, "setsockopt dontroute %d", tos);
8477f5f010bSBen Gras 
8487f5f010bSBen Gras 	/* Get the interface address list */
8497f5f010bSBen Gras 	n = ifaddrlist(&al, errbuf, sizeof errbuf);
8507f5f010bSBen Gras 	al2 = al;
8517f5f010bSBen Gras 	if (n < 0)
8527f5f010bSBen Gras 		errx(1, "ifaddrlist (%s)", errbuf);
8537f5f010bSBen Gras 	if (n == 0)
8547f5f010bSBen Gras 		errx(1, "Can't find any network interfaces");
8557f5f010bSBen Gras 
8567f5f010bSBen Gras 	/* Look for a specific device */
8577f5f010bSBen Gras 	if (device != NULL) {
8587f5f010bSBen Gras 		for (i = n; i > 0; --i, ++al2)
8597f5f010bSBen Gras 			if (strcmp(device, al2->device) == 0)
8607f5f010bSBen Gras 				break;
8617f5f010bSBen Gras 		if (i <= 0)
8627f5f010bSBen Gras 			errx(1, "Can't find interface %.32s", device);
8637f5f010bSBen Gras 	}
8647f5f010bSBen Gras 
8657f5f010bSBen Gras 	/* Determine our source address */
8667f5f010bSBen Gras 	if (source == NULL) {
8677f5f010bSBen Gras 		/*
8687f5f010bSBen Gras 		 * If a device was specified, use the interface address.
8697f5f010bSBen Gras 		 * Otherwise, try to determine our source address.
8707f5f010bSBen Gras 		 * Warn if there are more than one.
8717f5f010bSBen Gras 		 */
8727f5f010bSBen Gras 		setsin(from, al2->addr);
8737f5f010bSBen Gras 		if (n > 1 && device == NULL && !find_local_ip(from, to)) {
8747f5f010bSBen Gras 			warnx("Multiple interfaces found; using %s @ %s",
8757f5f010bSBen Gras 			    inet_ntoa(from->sin_addr), al2->device);
8767f5f010bSBen Gras 		}
8777f5f010bSBen Gras 	} else {
8787f5f010bSBen Gras 		hi = gethostinfo(source);
8797f5f010bSBen Gras 		source = hi->name;
8807f5f010bSBen Gras 		hi->name = NULL;
8817f5f010bSBen Gras 		if (device == NULL) {
8827f5f010bSBen Gras 			/*
8837f5f010bSBen Gras 			 * Use the first interface found.
8847f5f010bSBen Gras 			 * Warn if there are more than one.
8857f5f010bSBen Gras 			 */
8867f5f010bSBen Gras 			setsin(from, hi->addrs[0]);
8877f5f010bSBen Gras 			if (hi->n > 1)
8887f5f010bSBen Gras 				warnx("%s has multiple addresses; using %s",
8897f5f010bSBen Gras 				    source, inet_ntoa(from->sin_addr));
8907f5f010bSBen Gras 		} else {
8917f5f010bSBen Gras 			/*
8927f5f010bSBen Gras 			 * Make sure the source specified matches the
8937f5f010bSBen Gras 			 * interface address.
8947f5f010bSBen Gras 			 */
8957f5f010bSBen Gras 			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
8967f5f010bSBen Gras 				if (*ap == al2->addr)
8977f5f010bSBen Gras 					break;
8987f5f010bSBen Gras 			if (i <= 0)
8997f5f010bSBen Gras 				errx(1, "%s is not on interface %s",
9007f5f010bSBen Gras 				    source, device);
9017f5f010bSBen Gras 			setsin(from, *ap);
9027f5f010bSBen Gras 		}
9037f5f010bSBen Gras 		freehostinfo(hi);
9047f5f010bSBen Gras 	}
9057f5f010bSBen Gras 
9067f5f010bSBen Gras 	/* Revert to non-privileged user after opening sockets */
9077f5f010bSBen Gras 	setgid(getgid());
9087f5f010bSBen Gras 	setuid(getuid());
9097f5f010bSBen Gras 
9107f5f010bSBen Gras 	/*
9117f5f010bSBen Gras 	 * If not root, make sure source address matches a local interface.
9127f5f010bSBen Gras 	 * (The list of addresses produced by ifaddrlist() automatically
9137f5f010bSBen Gras 	 * excludes interfaces that are marked down and/or loopback.)
9147f5f010bSBen Gras 	 */
9157f5f010bSBen Gras 	if (getuid())  {
9167f5f010bSBen Gras 		al2 = al;
9177f5f010bSBen Gras 		for (i = n; i > 0; --i, ++al2)
9187f5f010bSBen Gras 			if (from->sin_addr.s_addr == al2->addr)
9197f5f010bSBen Gras 			    break;
9207f5f010bSBen Gras 		if (i <= 0)
9217f5f010bSBen Gras 			errx(1, "%s is not a valid local address "
9227f5f010bSBen Gras 			    "and you are not superuser.",
9237f5f010bSBen Gras 			    inet_ntoa(from->sin_addr));
9247f5f010bSBen Gras 	}
9257f5f010bSBen Gras 
9267f5f010bSBen Gras 	outip->ip_src = from->sin_addr;
9277f5f010bSBen Gras #ifndef IP_HDRINCL
9287f5f010bSBen Gras 	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0)
9297f5f010bSBen Gras 		err(1, "bind");
9307f5f010bSBen Gras #endif
9317f5f010bSBen Gras 
9327f5f010bSBen Gras 	if (as_path) {
9337f5f010bSBen Gras 		asn = as_setup(as_server);
9347f5f010bSBen Gras 		if (asn == NULL) {
9357f5f010bSBen Gras 			warnx("as_setup failed, AS# lookups disabled");
9367f5f010bSBen Gras 			(void)fflush(stderr);
9377f5f010bSBen Gras 			as_path = 0;
9387f5f010bSBen Gras 		}
9397f5f010bSBen Gras 	}
9407f5f010bSBen Gras 
9417f5f010bSBen Gras 	setuid(getuid());
9427f5f010bSBen Gras 	Fprintf(stderr, "%s to %s (%s)",
9437f5f010bSBen Gras 	    prog, hostname, inet_ntoa(to->sin_addr));
9447f5f010bSBen Gras 	if (source)
9457f5f010bSBen Gras 		Fprintf(stderr, " from %s", source);
9467f5f010bSBen Gras 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
9477f5f010bSBen Gras 	(void)fflush(stderr);
9487f5f010bSBen Gras 
9497f5f010bSBen Gras 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
9507f5f010bSBen Gras 		u_int32_t lastaddr = 0;
9517f5f010bSBen Gras 		int gotlastaddr = 0;
9527f5f010bSBen Gras 		int got_there = 0;
9537f5f010bSBen Gras 		int unreachable = 0;
9547f5f010bSBen Gras 		int sentfirst = 0;
9557f5f010bSBen Gras 
9567f5f010bSBen Gras again:
9577f5f010bSBen Gras 		printed_ttl = 0;
9587f5f010bSBen Gras 		for (probe = 0; probe < nprobes; ++probe) {
9597f5f010bSBen Gras 			int cc;
9607f5f010bSBen Gras 			struct timeval t1, t2;
9617f5f010bSBen Gras 			struct ip *ip;
9627f5f010bSBen Gras 			if (sentfirst && pausemsecs > 0)
9637f5f010bSBen Gras 				usleep(pausemsecs * 1000);
9647f5f010bSBen Gras 			(void)gettimeofday(&t1, NULL);
9657f5f010bSBen Gras 			if (!useicmp && htons(port + seq + 1) == 0)
9667f5f010bSBen Gras 				seq++;
9677f5f010bSBen Gras 			send_probe(++seq, ttl, &t1);
9687f5f010bSBen Gras 			++sentfirst;
9697f5f010bSBen Gras 			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
9707f5f010bSBen Gras 				(void)gettimeofday(&t2, NULL);
9717f5f010bSBen Gras 				/*
9727f5f010bSBen Gras 				 * Since we'll be receiving all ICMP
9737f5f010bSBen Gras 				 * messages to this host above, we may
9747f5f010bSBen Gras 				 * never end up with cc=0, so we need
9757f5f010bSBen Gras 				 * an additional termination check.
9767f5f010bSBen Gras 				 */
9777f5f010bSBen Gras 				if (t2.tv_sec - t1.tv_sec > waittime) {
9787f5f010bSBen Gras 					cc = 0;
9797f5f010bSBen Gras 					break;
9807f5f010bSBen Gras 				}
9817f5f010bSBen Gras 				i = packet_ok(packet, cc, from, seq);
9827f5f010bSBen Gras 				/* Skip short packet */
9837f5f010bSBen Gras 				if (i == 0)
9847f5f010bSBen Gras 					continue;
9857f5f010bSBen Gras 				if (!gotlastaddr ||
9867f5f010bSBen Gras 				    from->sin_addr.s_addr != lastaddr) {
9877f5f010bSBen Gras 					if (gotlastaddr) printf("\n   ");
9887f5f010bSBen Gras 					print(packet, cc, from);
9897f5f010bSBen Gras 					lastaddr = from->sin_addr.s_addr;
9907f5f010bSBen Gras 					++gotlastaddr;
9917f5f010bSBen Gras 				}
9927f5f010bSBen Gras 				ip = (struct ip *)packet;
9937f5f010bSBen Gras 				Printf("  %.3f ms", deltaT(&t1, &t2));
9947f5f010bSBen Gras 				if (ttl_flag)
9957f5f010bSBen Gras 					Printf(" (ttl = %d)", ip->ip_ttl);
9967f5f010bSBen Gras 				if (i == -2) {
9977f5f010bSBen Gras #ifndef ARCHAIC
9987f5f010bSBen Gras 					if (ip->ip_ttl <= 1)
9997f5f010bSBen Gras 						Printf(" !");
10007f5f010bSBen Gras #endif
10017f5f010bSBen Gras 					++got_there;
10027f5f010bSBen Gras 					break;
10037f5f010bSBen Gras 				}
10047f5f010bSBen Gras 
10057f5f010bSBen Gras 				/* time exceeded in transit */
10067f5f010bSBen Gras 				if (i == -1)
10077f5f010bSBen Gras 					break;
10087f5f010bSBen Gras 				code = i - 1;
10097f5f010bSBen Gras 				switch (code) {
10107f5f010bSBen Gras 
10117f5f010bSBen Gras 				case ICMP_UNREACH_PORT:
10127f5f010bSBen Gras #ifndef ARCHAIC
10137f5f010bSBen Gras 					if (ip->ip_ttl <= 1)
10147f5f010bSBen Gras 						Printf(" !");
10157f5f010bSBen Gras #endif
10167f5f010bSBen Gras 					++got_there;
10177f5f010bSBen Gras 					break;
10187f5f010bSBen Gras 
10197f5f010bSBen Gras 				case ICMP_UNREACH_NET:
10207f5f010bSBen Gras 					++unreachable;
10217f5f010bSBen Gras 					Printf(" !N");
10227f5f010bSBen Gras 					break;
10237f5f010bSBen Gras 
10247f5f010bSBen Gras 				case ICMP_UNREACH_HOST:
10257f5f010bSBen Gras 					++unreachable;
10267f5f010bSBen Gras 					Printf(" !H");
10277f5f010bSBen Gras 					break;
10287f5f010bSBen Gras 
10297f5f010bSBen Gras 				case ICMP_UNREACH_PROTOCOL:
10307f5f010bSBen Gras 					++got_there;
10317f5f010bSBen Gras 					Printf(" !P");
10327f5f010bSBen Gras 					break;
10337f5f010bSBen Gras 
10347f5f010bSBen Gras 				case ICMP_UNREACH_NEEDFRAG:
10357f5f010bSBen Gras 					if (mtudisc) {
10367f5f010bSBen Gras 						frag_err();
10377f5f010bSBen Gras 						goto again;
10387f5f010bSBen Gras 					} else {
10397f5f010bSBen Gras 						++unreachable;
10407f5f010bSBen Gras 						Printf(" !F-%d", pmtu);
10417f5f010bSBen Gras 					}
10427f5f010bSBen Gras 					break;
10437f5f010bSBen Gras 
10447f5f010bSBen Gras 				case ICMP_UNREACH_SRCFAIL:
10457f5f010bSBen Gras 					++unreachable;
10467f5f010bSBen Gras 					Printf(" !S");
10477f5f010bSBen Gras 					break;
10487f5f010bSBen Gras 
10497f5f010bSBen Gras 				case ICMP_UNREACH_FILTER_PROHIB:
10507f5f010bSBen Gras 					++unreachable;
10517f5f010bSBen Gras 					Printf(" !X");
10527f5f010bSBen Gras 					break;
10537f5f010bSBen Gras 
10547f5f010bSBen Gras 				case ICMP_UNREACH_HOST_PRECEDENCE:
10557f5f010bSBen Gras 					++unreachable;
10567f5f010bSBen Gras 					Printf(" !V");
10577f5f010bSBen Gras 					break;
10587f5f010bSBen Gras 
10597f5f010bSBen Gras 				case ICMP_UNREACH_PRECEDENCE_CUTOFF:
10607f5f010bSBen Gras 					++unreachable;
10617f5f010bSBen Gras 					Printf(" !C");
10627f5f010bSBen Gras 					break;
10637f5f010bSBen Gras 
10647f5f010bSBen Gras 				default:
10657f5f010bSBen Gras 					++unreachable;
10667f5f010bSBen Gras 					Printf(" !<%d>", code);
10677f5f010bSBen Gras 					break;
10687f5f010bSBen Gras 				}
10697f5f010bSBen Gras 				break;
10707f5f010bSBen Gras 			}
10717f5f010bSBen Gras 			if (cc == 0)
10727f5f010bSBen Gras 				Printf(" *");
10737f5f010bSBen Gras 			else if (cc && probe == nprobes - 1 && Mflag)
10747f5f010bSBen Gras 				decode_extensions(packet, cc);
10757f5f010bSBen Gras 			(void)fflush(stdout);
10767f5f010bSBen Gras 		}
10777f5f010bSBen Gras 		putchar('\n');
10787f5f010bSBen Gras 		if (got_there ||
10797f5f010bSBen Gras 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2)))
10807f5f010bSBen Gras 			break;
10817f5f010bSBen Gras 	}
10827f5f010bSBen Gras 
10837f5f010bSBen Gras 	if (as_path)
10847f5f010bSBen Gras 		as_shutdown(asn);
10857f5f010bSBen Gras 
10867f5f010bSBen Gras 	exit(0);
10877f5f010bSBen Gras }
10887f5f010bSBen Gras 
10897f5f010bSBen Gras static ssize_t
wait_for_reply(int sock,struct sockaddr_in * fromp,const struct timeval * tp)10907f5f010bSBen Gras wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
10917f5f010bSBen Gras {
10927f5f010bSBen Gras 	struct pollfd set[1];
10937f5f010bSBen Gras 	struct timeval now, wait;
10947f5f010bSBen Gras 	ssize_t cc = 0;
10957f5f010bSBen Gras 	socklen_t fromlen = sizeof(*fromp);
10967f5f010bSBen Gras 	int retval;
10977f5f010bSBen Gras 
10987f5f010bSBen Gras 	set[0].fd = sock;
10997f5f010bSBen Gras 	set[0].events = POLLIN;
11007f5f010bSBen Gras 
11017f5f010bSBen Gras 	wait.tv_sec = tp->tv_sec + waittime;
11027f5f010bSBen Gras 	wait.tv_usec = tp->tv_usec;
11037f5f010bSBen Gras 	(void)gettimeofday(&now, NULL);
11047f5f010bSBen Gras 	tvsub(&wait, &now);
11057f5f010bSBen Gras 
11067f5f010bSBen Gras 	if (wait.tv_sec < 0) {
11077f5f010bSBen Gras 		wait.tv_sec = 0;
11087f5f010bSBen Gras 		wait.tv_usec = 0;
11097f5f010bSBen Gras 	}
11107f5f010bSBen Gras 
11117f5f010bSBen Gras 	retval = prog_poll(set, 1, wait.tv_sec * 1000 + wait.tv_usec / 1000);
11127f5f010bSBen Gras 	if (retval < 0)
11137f5f010bSBen Gras 		/* If we continue, we probably just flood the remote host. */
11147f5f010bSBen Gras 		err(1, "poll");
11157f5f010bSBen Gras 	if (retval > 0)  {
11167f5f010bSBen Gras 		cc = prog_recvfrom(sock, (char *)packet, sizeof(packet), 0,
11177f5f010bSBen Gras 			    (struct sockaddr *)fromp, &fromlen);
11187f5f010bSBen Gras 	}
11197f5f010bSBen Gras 
11207f5f010bSBen Gras 	return cc;
11217f5f010bSBen Gras }
11227f5f010bSBen Gras 
11237f5f010bSBen Gras static void
decode_extensions(unsigned char * buf,int ip_len)11247f5f010bSBen Gras decode_extensions(unsigned char *buf, int ip_len)
11257f5f010bSBen Gras {
11267f5f010bSBen Gras         struct icmp_ext_cmn_hdr *cmn_hdr;
11277f5f010bSBen Gras         struct icmp_ext_obj_hdr *obj_hdr;
11287f5f010bSBen Gras         union {
11297f5f010bSBen Gras                 struct mpls_header mpls;
11307f5f010bSBen Gras                 uint32_t mpls_h;
11317f5f010bSBen Gras         } mpls;
11327f5f010bSBen Gras         size_t datalen, obj_len;
11337f5f010bSBen Gras         struct ip *ip;
11347f5f010bSBen Gras 
11357f5f010bSBen Gras         ip = (struct ip *)buf;
11367f5f010bSBen Gras 
11377f5f010bSBen Gras         if (ip_len < (int)((ip->ip_hl << 2) + ICMP_EXT_OFFSET +
11387f5f010bSBen Gras 	    sizeof(struct icmp_ext_cmn_hdr))) {
11397f5f010bSBen Gras 		/*
11407f5f010bSBen Gras 		 * No support for ICMP extensions on this host
11417f5f010bSBen Gras 		 */
11427f5f010bSBen Gras 		return;
11437f5f010bSBen Gras         }
11447f5f010bSBen Gras 
11457f5f010bSBen Gras         /*
11467f5f010bSBen Gras          * Move forward to the start of the ICMP extensions, if present
11477f5f010bSBen Gras          */
11487f5f010bSBen Gras         buf += (ip->ip_hl << 2) + ICMP_EXT_OFFSET;
11497f5f010bSBen Gras         cmn_hdr = (struct icmp_ext_cmn_hdr *)buf;
11507f5f010bSBen Gras 
11517f5f010bSBen Gras         if (cmn_hdr->version != ICMP_EXT_VERSION) {
11527f5f010bSBen Gras 		/*
11537f5f010bSBen Gras 		 * Unknown version
11547f5f010bSBen Gras 		 */
11557f5f010bSBen Gras 		return;
11567f5f010bSBen Gras         }
11577f5f010bSBen Gras 
11587f5f010bSBen Gras         datalen = ip_len - ((u_char *)cmn_hdr - (u_char *)ip);
11597f5f010bSBen Gras 
11607f5f010bSBen Gras         /*
11617f5f010bSBen Gras          * Check the checksum, cmn_hdr->checksum == 0 means no checksum'ing
11627f5f010bSBen Gras          * done by sender.
11637f5f010bSBen Gras          *
11647f5f010bSBen Gras         * If the checksum is ok, we'll get 0, as the checksum is calculated
11657f5f010bSBen Gras          * with the checksum field being 0'd.
11667f5f010bSBen Gras          */
11677f5f010bSBen Gras         if (ntohs(cmn_hdr->checksum) &&
11687f5f010bSBen Gras             in_cksum((u_short *)cmn_hdr, datalen)) {
11697f5f010bSBen Gras 
11707f5f010bSBen Gras             return;
11717f5f010bSBen Gras         }
11727f5f010bSBen Gras 
11737f5f010bSBen Gras         buf += sizeof(*cmn_hdr);
11747f5f010bSBen Gras         datalen -= sizeof(*cmn_hdr);
11757f5f010bSBen Gras 
11767f5f010bSBen Gras         while (datalen >= sizeof(struct icmp_ext_obj_hdr)) {
11777f5f010bSBen Gras 		obj_hdr = (struct icmp_ext_obj_hdr *)buf;
11787f5f010bSBen Gras 		obj_len = ntohs(obj_hdr->length);
11797f5f010bSBen Gras 
11807f5f010bSBen Gras 		/*
11817f5f010bSBen Gras 		 * Sanity check the length field
11827f5f010bSBen Gras 		 */
11837f5f010bSBen Gras 		if (obj_len > datalen)
11847f5f010bSBen Gras 			return;
11857f5f010bSBen Gras 
11867f5f010bSBen Gras 		datalen -= obj_len;
11877f5f010bSBen Gras 
11887f5f010bSBen Gras 		/*
11897f5f010bSBen Gras 		 * Move past the object header
11907f5f010bSBen Gras 		 */
11917f5f010bSBen Gras 		buf += sizeof(struct icmp_ext_obj_hdr);
11927f5f010bSBen Gras 		obj_len -= sizeof(struct icmp_ext_obj_hdr);
11937f5f010bSBen Gras 
11947f5f010bSBen Gras 		switch (obj_hdr->class_num) {
11957f5f010bSBen Gras 		case MPLS_STACK_ENTRY_CLASS:
11967f5f010bSBen Gras 			switch (obj_hdr->c_type) {
11977f5f010bSBen Gras 			case MPLS_STACK_ENTRY_C_TYPE:
11987f5f010bSBen Gras 				while (obj_len >= sizeof(uint32_t)) {
11997f5f010bSBen Gras 					mpls.mpls_h = ntohl(*(uint32_t *)buf);
12007f5f010bSBen Gras 
12017f5f010bSBen Gras 					buf += sizeof(uint32_t);
12027f5f010bSBen Gras 					obj_len -= sizeof(uint32_t);
12037f5f010bSBen Gras 
12047f5f010bSBen Gras 					printf(" [MPLS: Label %d Exp %d]",
12057f5f010bSBen Gras 					    mpls.mpls.label, mpls.mpls.exp);
12067f5f010bSBen Gras 				}
12077f5f010bSBen Gras 				if (obj_len > 0) {
12087f5f010bSBen Gras 					/*
12097f5f010bSBen Gras 					 * Something went wrong, and we're at
12107f5f010bSBen Gras 					 * a unknown offset into the packet,
12117f5f010bSBen Gras 					 * ditch the rest of it.
12127f5f010bSBen Gras 					 */
12137f5f010bSBen Gras 					return;
12147f5f010bSBen Gras 				}
12157f5f010bSBen Gras 				break;
12167f5f010bSBen Gras 			default:
12177f5f010bSBen Gras 				/*
12187f5f010bSBen Gras 				 * Unknown object, skip past it
12197f5f010bSBen Gras 				 */
12207f5f010bSBen Gras 				buf += ntohs(obj_hdr->length) -
12217f5f010bSBen Gras 				    sizeof(struct icmp_ext_obj_hdr);
12227f5f010bSBen Gras 				break;
12237f5f010bSBen Gras 			}
12247f5f010bSBen Gras 			break;
12257f5f010bSBen Gras 
12267f5f010bSBen Gras 		default:
12277f5f010bSBen Gras 			/*
12287f5f010bSBen Gras 			 * Unknown object, skip past it
12297f5f010bSBen Gras 			 */
12307f5f010bSBen Gras 			buf += ntohs(obj_hdr->length) -
12317f5f010bSBen Gras 			    sizeof(struct icmp_ext_obj_hdr);
12327f5f010bSBen Gras 			break;
12337f5f010bSBen Gras 		}
12347f5f010bSBen Gras 	}
12357f5f010bSBen Gras }
12367f5f010bSBen Gras 
12377f5f010bSBen Gras static void
dump_packet(void)12387f5f010bSBen Gras dump_packet(void)
12397f5f010bSBen Gras {
12407f5f010bSBen Gras 	u_char *p;
12417f5f010bSBen Gras 	int i;
12427f5f010bSBen Gras 
12437f5f010bSBen Gras 	Fprintf(stderr, "packet data:");
12447f5f010bSBen Gras 
12457f5f010bSBen Gras #ifdef __hpux
12467f5f010bSBen Gras 	for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i <
12477f5f010bSBen Gras 	    i < packlen - (sizeof(*outip) + optlen); i++)
12487f5f010bSBen Gras #else
12497f5f010bSBen Gras 	for (p = (u_char *)outip, i = 0; i < packlen; i++)
12507f5f010bSBen Gras #endif
12517f5f010bSBen Gras 	{
12527f5f010bSBen Gras 		if ((i % 24) == 0)
12537f5f010bSBen Gras 			Fprintf(stderr, "\n ");
12547f5f010bSBen Gras 		Fprintf(stderr, " %02x", *p++);
12557f5f010bSBen Gras 	}
12567f5f010bSBen Gras 	Fprintf(stderr, "\n");
12577f5f010bSBen Gras }
12587f5f010bSBen Gras 
12597f5f010bSBen Gras void
send_probe(int seq,int ttl,struct timeval * tp)12607f5f010bSBen Gras send_probe(int seq, int ttl, struct timeval *tp)
12617f5f010bSBen Gras {
12627f5f010bSBen Gras 	int cc;
12637f5f010bSBen Gras 	struct udpiphdr * ui, *oui;
12647f5f010bSBen Gras 	int oldmtu = packlen;
12657f5f010bSBen Gras  	struct ip tip;
12667f5f010bSBen Gras 
12677f5f010bSBen Gras again:
12687f5f010bSBen Gras #ifdef BYTESWAP_IP_LEN
12697f5f010bSBen Gras 	outip->ip_len = htons(packlen);
12707f5f010bSBen Gras #else
12717f5f010bSBen Gras 	outip->ip_len = packlen;
12727f5f010bSBen Gras #endif
12737f5f010bSBen Gras 	outip->ip_ttl = ttl;
12747f5f010bSBen Gras #ifndef __hpux
12757f5f010bSBen Gras 	outip->ip_id = htons(ident + seq);
12767f5f010bSBen Gras #endif
12777f5f010bSBen Gras 
12787f5f010bSBen Gras 	/*
12797f5f010bSBen Gras 	 * In most cases, the kernel will recalculate the ip checksum.
12807f5f010bSBen Gras 	 * But we must do it anyway so that the udp checksum comes out
12817f5f010bSBen Gras 	 * right.
12827f5f010bSBen Gras 	 */
12837f5f010bSBen Gras 	if (doipcksum) {
12847f5f010bSBen Gras 		outip->ip_sum =
12857f5f010bSBen Gras 		    in_cksum((u_int16_t *)outip, sizeof(*outip) + optlen);
12867f5f010bSBen Gras 		if (outip->ip_sum == 0)
12877f5f010bSBen Gras 			outip->ip_sum = 0xffff;
12887f5f010bSBen Gras 	}
12897f5f010bSBen Gras 
12907f5f010bSBen Gras 	/* Payload */
12917f5f010bSBen Gras 	outsetup.seq = seq;
12927f5f010bSBen Gras 	outsetup.ttl = ttl;
12937f5f010bSBen Gras 	outsetup.tv.tv32_sec = htonl(tp->tv_sec);
12947f5f010bSBen Gras 	outsetup.tv.tv32_usec = htonl(tp->tv_usec);
12957f5f010bSBen Gras 	memcpy(outmark,&outsetup,sizeof(outsetup));
12967f5f010bSBen Gras 
12977f5f010bSBen Gras 	if (useicmp)
12987f5f010bSBen Gras 		outicmp->icmp_seq = htons(seq);
12997f5f010bSBen Gras 	else
13007f5f010bSBen Gras 		outudp->uh_dport = htons(port + seq);
13017f5f010bSBen Gras 
13027f5f010bSBen Gras 	if (useicmp) {
13037f5f010bSBen Gras 		/* Always calculate checksum for icmp packets */
13047f5f010bSBen Gras 		outicmp->icmp_cksum = 0;
13057f5f010bSBen Gras 		outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
13067f5f010bSBen Gras 		    packlen - (sizeof(*outip) + optlen));
13077f5f010bSBen Gras 		if (outicmp->icmp_cksum == 0)
13087f5f010bSBen Gras 			outicmp->icmp_cksum = 0xffff;
13097f5f010bSBen Gras 	} else if (doipcksum) {
13107f5f010bSBen Gras 		/* Checksum (we must save and restore ip header) */
13117f5f010bSBen Gras 		tip = *outip;
13127f5f010bSBen Gras 		ui = (struct udpiphdr *)outip;
13137f5f010bSBen Gras 		oui = (struct udpiphdr *)&tip;
13147f5f010bSBen Gras 		/* Easier to zero and put back things that are ok */
13157f5f010bSBen Gras 		memset(ui, 0, sizeof(ui->ui_i));
13167f5f010bSBen Gras 		ui->ui_src = oui->ui_src;
13177f5f010bSBen Gras 		ui->ui_dst = oui->ui_dst;
13187f5f010bSBen Gras 		ui->ui_pr = oui->ui_pr;
13197f5f010bSBen Gras 		ui->ui_len = outudp->uh_ulen;
13207f5f010bSBen Gras 		outudp->uh_sum = 0;
13217f5f010bSBen Gras 		outudp->uh_sum = in_cksum((u_short *)ui, packlen);
13227f5f010bSBen Gras 		if (outudp->uh_sum == 0)
13237f5f010bSBen Gras 			outudp->uh_sum = 0xffff;
13247f5f010bSBen Gras 		*outip = tip;
13257f5f010bSBen Gras 	}
13267f5f010bSBen Gras 
13277f5f010bSBen Gras 	/* XXX undocumented debugging hack */
13287f5f010bSBen Gras 	if (verbose > 1) {
13297f5f010bSBen Gras 		const u_int16_t *sp;
13307f5f010bSBen Gras 		int nshorts, i;
13317f5f010bSBen Gras 
13327f5f010bSBen Gras 		sp = (u_int16_t *)outip;
13337f5f010bSBen Gras 		nshorts = (u_int)packlen / sizeof(u_int16_t);
13347f5f010bSBen Gras 		i = 0;
13357f5f010bSBen Gras 		Printf("[ %d bytes", packlen);
13367f5f010bSBen Gras 		while (--nshorts >= 0) {
13377f5f010bSBen Gras 			if ((i++ % 8) == 0)
13387f5f010bSBen Gras 				Printf("\n\t");
13397f5f010bSBen Gras 			Printf(" %04x", ntohs(*sp++));
13407f5f010bSBen Gras 		}
13417f5f010bSBen Gras 		if (packlen & 1) {
13427f5f010bSBen Gras 			if ((i % 8) == 0)
13437f5f010bSBen Gras 				Printf("\n\t");
13447f5f010bSBen Gras 			Printf(" %02x", *(const u_char *)sp);
13457f5f010bSBen Gras 		}
13467f5f010bSBen Gras 		Printf("]\n");
13477f5f010bSBen Gras 	}
13487f5f010bSBen Gras 
13497f5f010bSBen Gras #if !defined(IP_HDRINCL) && defined(IP_TTL)
13507f5f010bSBen Gras 	if (prog_setsockopt(sndsock, IPPROTO_IP, IP_TTL,
13517f5f010bSBen Gras 	    (char *)&ttl, sizeof(ttl)) < 0)
13527f5f010bSBen Gras 		err(1, "setsockopt ttl %d", ttl);
13537f5f010bSBen Gras #endif
13547f5f010bSBen Gras 	if (dump)
13557f5f010bSBen Gras 		dump_packet();
13567f5f010bSBen Gras 
13577f5f010bSBen Gras #ifdef __hpux
13587f5f010bSBen Gras 	cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
13597f5f010bSBen Gras 	    packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
13607f5f010bSBen Gras 	if (cc > 0)
13617f5f010bSBen Gras 		cc += sizeof(*outip) + optlen;
13627f5f010bSBen Gras #else
13637f5f010bSBen Gras 	cc = prog_sendto(sndsock, (char *)outip,
13647f5f010bSBen Gras 	    packlen, 0, &whereto, sizeof(whereto));
13657f5f010bSBen Gras #endif
13667f5f010bSBen Gras 	if (cc < 0 || cc != packlen)  {
13677f5f010bSBen Gras 		if (cc < 0) {
13687f5f010bSBen Gras 			/*
13697f5f010bSBen Gras 			 * An errno of EMSGSIZE means we're writing too big a
13707f5f010bSBen Gras 			 * datagram for the interface.  We have to just
13717f5f010bSBen Gras 			 * decrease the packet size until we find one that
13727f5f010bSBen Gras 			 * works.
13737f5f010bSBen Gras 			 *
13747f5f010bSBen Gras 			 * XXX maybe we should try to read the outgoing if's
13757f5f010bSBen Gras 			 * mtu?
13767f5f010bSBen Gras 			 */
13777f5f010bSBen Gras 			if (errno == EMSGSIZE) {
13787f5f010bSBen Gras 				packlen = *mtuptr++;
13797f5f010bSBen Gras 				resize_packet();
13807f5f010bSBen Gras 				goto again;
13817f5f010bSBen Gras 			} else
1382*0a6a1f1dSLionel Sambuc 				warn("sendto");
13837f5f010bSBen Gras 		}
13847f5f010bSBen Gras 
13857f5f010bSBen Gras 		Printf("%s: wrote %s %d chars, ret=%d\n",
13867f5f010bSBen Gras 		    prog, hostname, packlen, cc);
13877f5f010bSBen Gras 		(void)fflush(stdout);
13887f5f010bSBen Gras 	}
13897f5f010bSBen Gras 	if (oldmtu != packlen) {
13907f5f010bSBen Gras 		Printf("message too big, "
13917f5f010bSBen Gras 		    "trying new MTU = %d\n", packlen);
13927f5f010bSBen Gras 		printed_ttl = 0;
13937f5f010bSBen Gras 	}
13947f5f010bSBen Gras 	if (!printed_ttl) {
13957f5f010bSBen Gras 		Printf("%2d ", ttl);
13967f5f010bSBen Gras 		printed_ttl = 1;
13977f5f010bSBen Gras 	}
13987f5f010bSBen Gras 
13997f5f010bSBen Gras }
14007f5f010bSBen Gras 
14017f5f010bSBen Gras static double
deltaT(struct timeval * t1p,struct timeval * t2p)14027f5f010bSBen Gras deltaT(struct timeval *t1p, struct timeval *t2p)
14037f5f010bSBen Gras {
14047f5f010bSBen Gras 	double dt;
14057f5f010bSBen Gras 
14067f5f010bSBen Gras 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
14077f5f010bSBen Gras 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
14087f5f010bSBen Gras 	return dt;
14097f5f010bSBen Gras }
14107f5f010bSBen Gras 
14117f5f010bSBen Gras /*
14127f5f010bSBen Gras  * Convert an ICMP "type" field to a printable string.
14137f5f010bSBen Gras  */
14147f5f010bSBen Gras static const char *
pr_type(u_char t)14157f5f010bSBen Gras pr_type(u_char t)
14167f5f010bSBen Gras {
14177f5f010bSBen Gras 	static const char *ttab[] = {
14187f5f010bSBen Gras 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
14197f5f010bSBen Gras 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
14207f5f010bSBen Gras 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
14217f5f010bSBen Gras 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
14227f5f010bSBen Gras 	"Info Reply"
14237f5f010bSBen Gras 	};
14247f5f010bSBen Gras 
14257f5f010bSBen Gras 	if (t > 16)
14267f5f010bSBen Gras 		return "OUT-OF-RANGE";
14277f5f010bSBen Gras 
14287f5f010bSBen Gras 	return ttab[t];
14297f5f010bSBen Gras }
14307f5f010bSBen Gras 
14317f5f010bSBen Gras static int
packet_ok(u_char * buf,ssize_t cc,struct sockaddr_in * from,int seq)14327f5f010bSBen Gras packet_ok(u_char *buf, ssize_t cc, struct sockaddr_in *from, int seq)
14337f5f010bSBen Gras {
14347f5f010bSBen Gras 	struct icmp *icp;
14357f5f010bSBen Gras 	u_char type, code;
14367f5f010bSBen Gras 	int hlen;
14377f5f010bSBen Gras #ifndef ARCHAIC
14387f5f010bSBen Gras 	struct ip *ip;
14397f5f010bSBen Gras 
14407f5f010bSBen Gras 	ip = (struct ip *) buf;
14417f5f010bSBen Gras 	hlen = ip->ip_hl << 2;
14427f5f010bSBen Gras 	if (cc < hlen + ICMP_MINLEN) {
14437f5f010bSBen Gras 		if (verbose)
14447f5f010bSBen Gras 			Printf("packet too short (%zd bytes) from %s\n", cc,
14457f5f010bSBen Gras 				inet_ntoa(from->sin_addr));
14467f5f010bSBen Gras 		return 0;
14477f5f010bSBen Gras 	}
14487f5f010bSBen Gras 	cc -= hlen;
14497f5f010bSBen Gras 	icp = (struct icmp *)(buf + hlen);
14507f5f010bSBen Gras #else
14517f5f010bSBen Gras 	icp = (struct icmp *)buf;
14527f5f010bSBen Gras #endif
14537f5f010bSBen Gras 	type = icp->icmp_type;
14547f5f010bSBen Gras 	code = icp->icmp_code;
14557f5f010bSBen Gras 	/* Path MTU Discovery (RFC1191) */
14567f5f010bSBen Gras 	if (code != ICMP_UNREACH_NEEDFRAG)
14577f5f010bSBen Gras 		pmtu = 0;
14587f5f010bSBen Gras 	else {
14597f5f010bSBen Gras #ifdef HAVE_ICMP_NEXTMTU
14607f5f010bSBen Gras 		pmtu = ntohs(icp->icmp_nextmtu);
14617f5f010bSBen Gras #else
14627f5f010bSBen Gras 		pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
14637f5f010bSBen Gras #endif
14647f5f010bSBen Gras 	}
14657f5f010bSBen Gras 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
14667f5f010bSBen Gras 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
14677f5f010bSBen Gras 		struct ip *hip;
14687f5f010bSBen Gras 		struct udphdr *up;
14697f5f010bSBen Gras 		struct icmp *hicmp;
14707f5f010bSBen Gras 
14717f5f010bSBen Gras 		hip = &icp->icmp_ip;
14727f5f010bSBen Gras 		hlen = hip->ip_hl << 2;
14737f5f010bSBen Gras 
14747f5f010bSBen Gras 		nextmtu = ntohs(icp->icmp_nextmtu);	/* for frag_err() */
14757f5f010bSBen Gras 
14767f5f010bSBen Gras 		if (useicmp) {
14777f5f010bSBen Gras 			/* XXX */
14787f5f010bSBen Gras 			if (type == ICMP_ECHOREPLY &&
14797f5f010bSBen Gras 			    icp->icmp_id == htons(ident) &&
14807f5f010bSBen Gras 			    icp->icmp_seq == htons(seq))
14817f5f010bSBen Gras 				return -2;
14827f5f010bSBen Gras 
14837f5f010bSBen Gras 			hicmp = (struct icmp *)((u_char *)hip + hlen);
14847f5f010bSBen Gras 			/* XXX 8 is a magic number */
14857f5f010bSBen Gras 			if (hlen + 8 <= cc &&
14867f5f010bSBen Gras 			    hip->ip_p == IPPROTO_ICMP &&
14877f5f010bSBen Gras 			    hicmp->icmp_id == htons(ident) &&
14887f5f010bSBen Gras 			    hicmp->icmp_seq == htons(seq))
14897f5f010bSBen Gras 				return type == ICMP_TIMXCEED ? -1 : code + 1;
14907f5f010bSBen Gras 		} else {
14917f5f010bSBen Gras 			up = (struct udphdr *)((u_char *)hip + hlen);
14927f5f010bSBen Gras 			/* XXX 8 is a magic number */
14937f5f010bSBen Gras 			if (hlen + 12 <= cc &&
14947f5f010bSBen Gras 			    hip->ip_p == IPPROTO_UDP &&
14957f5f010bSBen Gras 			    up->uh_sport == htons(ident) &&
14967f5f010bSBen Gras 			    up->uh_dport == htons(port + seq))
14977f5f010bSBen Gras 				return type == ICMP_TIMXCEED ? -1 : code + 1;
14987f5f010bSBen Gras 		}
14997f5f010bSBen Gras 	}
15007f5f010bSBen Gras #ifndef ARCHAIC
15017f5f010bSBen Gras 	if (verbose) {
15027f5f010bSBen Gras 		int i;
15037f5f010bSBen Gras 		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
15047f5f010bSBen Gras 
15057f5f010bSBen Gras 		Printf("\n%zd bytes from %s to ", cc, inet_ntoa(from->sin_addr));
15067f5f010bSBen Gras 		Printf("%s: icmp type %d (%s) code %d\n",
15077f5f010bSBen Gras 		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
15087f5f010bSBen Gras 		for (i = 4; i < cc ; i += sizeof(*lp))
15097f5f010bSBen Gras 			Printf("%2d: x%8.8x\n", i, *lp++);
15107f5f010bSBen Gras 	}
15117f5f010bSBen Gras #endif
15127f5f010bSBen Gras 	return(0);
15137f5f010bSBen Gras }
15147f5f010bSBen Gras 
15157f5f010bSBen Gras static void
resize_packet(void)15167f5f010bSBen Gras resize_packet(void)
15177f5f010bSBen Gras {
15187f5f010bSBen Gras 	if (useicmp) {
15197f5f010bSBen Gras 		outicmp->icmp_cksum = 0;
15207f5f010bSBen Gras 		outicmp->icmp_cksum = in_cksum((u_int16_t *)outicmp,
15217f5f010bSBen Gras 		    packlen - (sizeof(*outip) + optlen));
15227f5f010bSBen Gras 		if (outicmp->icmp_cksum == 0)
15237f5f010bSBen Gras 			outicmp->icmp_cksum = 0xffff;
15247f5f010bSBen Gras 	} else {
15257f5f010bSBen Gras 		outudp->uh_ulen =
15267f5f010bSBen Gras 		    htons((u_int16_t)(packlen - (sizeof(*outip) + optlen)));
15277f5f010bSBen Gras 	}
15287f5f010bSBen Gras }
15297f5f010bSBen Gras 
15307f5f010bSBen Gras static void
print(u_char * buf,int cc,struct sockaddr_in * from)15317f5f010bSBen Gras print(u_char *buf, int cc, struct sockaddr_in *from)
15327f5f010bSBen Gras {
15337f5f010bSBen Gras 	struct ip *ip;
15347f5f010bSBen Gras 	int hlen;
15357f5f010bSBen Gras 	char addr[INET_ADDRSTRLEN];
15367f5f010bSBen Gras 
15377f5f010bSBen Gras 	ip = (struct ip *) buf;
15387f5f010bSBen Gras 	hlen = ip->ip_hl << 2;
15397f5f010bSBen Gras 	cc -= hlen;
15407f5f010bSBen Gras 
15417f5f010bSBen Gras 	strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
15427f5f010bSBen Gras 
15437f5f010bSBen Gras 	if (as_path)
15447f5f010bSBen Gras 		Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
15457f5f010bSBen Gras 
15467f5f010bSBen Gras 	if (nflag)
15477f5f010bSBen Gras 		Printf(" %s", addr);
15487f5f010bSBen Gras 	else
15497f5f010bSBen Gras 		Printf(" %s (%s)", inetname(from->sin_addr), addr);
15507f5f010bSBen Gras 
15517f5f010bSBen Gras 	if (verbose)
15527f5f010bSBen Gras 		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
15537f5f010bSBen Gras }
15547f5f010bSBen Gras 
15557f5f010bSBen Gras static u_int16_t
in_cksum(u_int16_t * addr,int len)15567f5f010bSBen Gras in_cksum(u_int16_t *addr, int len)
15577f5f010bSBen Gras {
15587f5f010bSBen Gras 
15597f5f010bSBen Gras 	return ~in_cksum2(0, addr, len);
15607f5f010bSBen Gras }
15617f5f010bSBen Gras 
15627f5f010bSBen Gras /*
15637f5f010bSBen Gras  * Checksum routine for Internet Protocol family headers (C Version)
15647f5f010bSBen Gras  */
15657f5f010bSBen Gras static u_int16_t
in_cksum2(u_int16_t seed,u_int16_t * addr,int len)15667f5f010bSBen Gras in_cksum2(u_int16_t seed, u_int16_t *addr, int len)
15677f5f010bSBen Gras {
15687f5f010bSBen Gras 	int nleft = len;
15697f5f010bSBen Gras 	u_int16_t *w = addr;
15707f5f010bSBen Gras 	union {
15717f5f010bSBen Gras 		u_int16_t w;
15727f5f010bSBen Gras 		u_int8_t b[2];
15737f5f010bSBen Gras 	} answer;
15747f5f010bSBen Gras 	int32_t sum = seed;
15757f5f010bSBen Gras 
15767f5f010bSBen Gras 	/*
15777f5f010bSBen Gras 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
15787f5f010bSBen Gras 	 *  we add sequential 16 bit words to it, and at the end, fold
15797f5f010bSBen Gras 	 *  back all the carry bits from the top 16 bits into the lower
15807f5f010bSBen Gras 	 *  16 bits.
15817f5f010bSBen Gras 	 */
15827f5f010bSBen Gras 	while (nleft > 1)  {
15837f5f010bSBen Gras 		sum += *w++;
15847f5f010bSBen Gras 		nleft -= 2;
15857f5f010bSBen Gras 	}
15867f5f010bSBen Gras 
15877f5f010bSBen Gras 	/* mop up an odd byte, if necessary */
15887f5f010bSBen Gras 	if (nleft == 1) {
15897f5f010bSBen Gras 		answer.b[0] = *(u_char *)w;
15907f5f010bSBen Gras 		answer.b[1] = 0;
15917f5f010bSBen Gras 		sum += answer.w;
15927f5f010bSBen Gras 	}
15937f5f010bSBen Gras 
15947f5f010bSBen Gras 	/*
15957f5f010bSBen Gras 	 * add back carry outs from top 16 bits to low 16 bits
15967f5f010bSBen Gras 	 */
15977f5f010bSBen Gras 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
15987f5f010bSBen Gras 	sum += (sum >> 16);			/* add carry */
15997f5f010bSBen Gras 	answer.w = sum;				/* truncate to 16 bits */
16007f5f010bSBen Gras 	return answer.w;
16017f5f010bSBen Gras }
16027f5f010bSBen Gras 
16037f5f010bSBen Gras /*
16047f5f010bSBen Gras  * Subtract 2 timeval structs:  out = out - in.
16057f5f010bSBen Gras  * Out is assumed to be >= in.
16067f5f010bSBen Gras  */
16077f5f010bSBen Gras static void
tvsub(struct timeval * out,struct timeval * in)16087f5f010bSBen Gras tvsub(struct timeval *out, struct timeval *in)
16097f5f010bSBen Gras {
16107f5f010bSBen Gras 
16117f5f010bSBen Gras 	if ((out->tv_usec -= in->tv_usec) < 0)   {
16127f5f010bSBen Gras 		--out->tv_sec;
16137f5f010bSBen Gras 		out->tv_usec += 1000000;
16147f5f010bSBen Gras 	}
16157f5f010bSBen Gras 	out->tv_sec -= in->tv_sec;
16167f5f010bSBen Gras }
16177f5f010bSBen Gras 
16187f5f010bSBen Gras /*
16197f5f010bSBen Gras  * Construct an Internet address representation.
16207f5f010bSBen Gras  * If the nflag has been supplied, give
16217f5f010bSBen Gras  * numeric value, otherwise try for symbolic name.
16227f5f010bSBen Gras  */
16237f5f010bSBen Gras static char *
inetname(struct in_addr in)16247f5f010bSBen Gras inetname(struct in_addr in)
16257f5f010bSBen Gras {
16267f5f010bSBen Gras 	char *cp;
16277f5f010bSBen Gras 	struct hostent *hp;
16287f5f010bSBen Gras 	static int first = 1;
16297f5f010bSBen Gras 	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
16307f5f010bSBen Gras 
16317f5f010bSBen Gras 	if (first && !nflag) {
16327f5f010bSBen Gras 
16337f5f010bSBen Gras 		first = 0;
16347f5f010bSBen Gras 		if (gethostname(domain, sizeof(domain) - 1) < 0)
16357f5f010bSBen Gras  			domain[0] = '\0';
16367f5f010bSBen Gras 		else {
16377f5f010bSBen Gras 			cp = strchr(domain, '.');
16387f5f010bSBen Gras 			if (cp == NULL) {
16397f5f010bSBen Gras 				hp = gethostbyname(domain);
16407f5f010bSBen Gras 				if (hp != NULL)
16417f5f010bSBen Gras 					cp = strchr(hp->h_name, '.');
16427f5f010bSBen Gras 			}
16437f5f010bSBen Gras 			if (cp == NULL)
16447f5f010bSBen Gras 				domain[0] = '\0';
16457f5f010bSBen Gras 			else {
16467f5f010bSBen Gras 				++cp;
16477f5f010bSBen Gras 				(void)strlcpy(domain, cp, sizeof(domain));
16487f5f010bSBen Gras 			}
16497f5f010bSBen Gras 		}
16507f5f010bSBen Gras 	}
16517f5f010bSBen Gras 	if (!nflag && in.s_addr != INADDR_ANY) {
16527f5f010bSBen Gras 		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
16537f5f010bSBen Gras 		if (hp != NULL) {
16547f5f010bSBen Gras 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
16557f5f010bSBen Gras 			    strcmp(cp + 1, domain) == 0)
16567f5f010bSBen Gras 				*cp = '\0';
16577f5f010bSBen Gras 			(void)strlcpy(line, hp->h_name, sizeof(line));
16587f5f010bSBen Gras 			return line;
16597f5f010bSBen Gras 		}
16607f5f010bSBen Gras 	}
16617f5f010bSBen Gras 	return inet_ntoa(in);
16627f5f010bSBen Gras }
16637f5f010bSBen Gras 
16647f5f010bSBen Gras static struct hostinfo *
gethostinfo(char * hname)16657f5f010bSBen Gras gethostinfo(char *hname)
16667f5f010bSBen Gras {
16677f5f010bSBen Gras 	int n;
16687f5f010bSBen Gras 	struct hostent *hp;
16697f5f010bSBen Gras 	struct hostinfo *hi;
16707f5f010bSBen Gras 	char **p;
16717f5f010bSBen Gras 	u_int32_t *ap;
16727f5f010bSBen Gras 	struct in_addr addr;
16737f5f010bSBen Gras 
16747f5f010bSBen Gras 	hi = calloc(1, sizeof(*hi));
16757f5f010bSBen Gras 	if (hi == NULL)
16767f5f010bSBen Gras 		err(1, "calloc");
16777f5f010bSBen Gras 	if (inet_aton(hname, &addr) != 0) {
16787f5f010bSBen Gras 		hi->name = strdup(hname);
16797f5f010bSBen Gras 		if (!hi->name)
16807f5f010bSBen Gras 			err(1, "strdup");
16817f5f010bSBen Gras 		hi->n = 1;
16827f5f010bSBen Gras 		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
16837f5f010bSBen Gras 		if (hi->addrs == NULL)
16847f5f010bSBen Gras 			err(1, "calloc");
16857f5f010bSBen Gras 		hi->addrs[0] = addr.s_addr;
16867f5f010bSBen Gras 		return hi;
16877f5f010bSBen Gras 	}
16887f5f010bSBen Gras 
16897f5f010bSBen Gras 	hp = gethostbyname(hname);
16907f5f010bSBen Gras 	if (hp == NULL)
16917f5f010bSBen Gras 		errx(1, "unknown host %s", hname);
16927f5f010bSBen Gras 	if (hp->h_addrtype != AF_INET || hp->h_length != 4)
16937f5f010bSBen Gras 		errx(1, "bad host %s", hname);
16947f5f010bSBen Gras 	hi->name = strdup(hp->h_name);
16957f5f010bSBen Gras 	if (!hi->name)
16967f5f010bSBen Gras 		err(1, "strdup");
16977f5f010bSBen Gras 	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
16987f5f010bSBen Gras 		continue;
16997f5f010bSBen Gras 	hi->n = n;
17007f5f010bSBen Gras 	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
17017f5f010bSBen Gras 	if (hi->addrs == NULL)
17027f5f010bSBen Gras 		err(1, "calloc");
17037f5f010bSBen Gras 	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
17047f5f010bSBen Gras 		memcpy(ap, *p, sizeof(*ap));
17057f5f010bSBen Gras 	return hi;
17067f5f010bSBen Gras }
17077f5f010bSBen Gras 
17087f5f010bSBen Gras static void
freehostinfo(struct hostinfo * hi)17097f5f010bSBen Gras freehostinfo(struct hostinfo *hi)
17107f5f010bSBen Gras {
17117f5f010bSBen Gras 	if (hi->name != NULL) {
17127f5f010bSBen Gras 		free(hi->name);
17137f5f010bSBen Gras 		hi->name = NULL;
17147f5f010bSBen Gras 	}
17157f5f010bSBen Gras 	free(hi->addrs);
17167f5f010bSBen Gras 	free(hi);
17177f5f010bSBen Gras }
17187f5f010bSBen Gras 
17197f5f010bSBen Gras static void
getaddr(u_int32_t * ap,char * hname)17207f5f010bSBen Gras getaddr(u_int32_t *ap, char *hname)
17217f5f010bSBen Gras {
17227f5f010bSBen Gras 	struct hostinfo *hi;
17237f5f010bSBen Gras 
17247f5f010bSBen Gras 	hi = gethostinfo(hname);
17257f5f010bSBen Gras 	*ap = hi->addrs[0];
17267f5f010bSBen Gras 	freehostinfo(hi);
17277f5f010bSBen Gras }
17287f5f010bSBen Gras 
17297f5f010bSBen Gras static void
setsin(struct sockaddr_in * sin,u_int32_t addr)17307f5f010bSBen Gras setsin(struct sockaddr_in *sin, u_int32_t addr)
17317f5f010bSBen Gras {
17327f5f010bSBen Gras 
17337f5f010bSBen Gras 	memset(sin, 0, sizeof(*sin));
17347f5f010bSBen Gras #ifdef HAVE_SOCKADDR_SA_LEN
17357f5f010bSBen Gras 	sin->sin_len = sizeof(*sin);
17367f5f010bSBen Gras #endif
17377f5f010bSBen Gras 	sin->sin_family = AF_INET;
17387f5f010bSBen Gras 	sin->sin_addr.s_addr = addr;
17397f5f010bSBen Gras }
17407f5f010bSBen Gras 
17417f5f010bSBen Gras /* String to value with optional min and max. Handles decimal and hex. */
17427f5f010bSBen Gras static int
str2val(const char * str,const char * what,int mi,int ma)17437f5f010bSBen Gras str2val(const char *str, const char *what, int mi, int ma)
17447f5f010bSBen Gras {
17457f5f010bSBen Gras 	const char *cp;
17467f5f010bSBen Gras 	long val;
17477f5f010bSBen Gras 	char *ep;
17487f5f010bSBen Gras 
17497f5f010bSBen Gras 	errno = 0;
17507f5f010bSBen Gras 	ep = NULL;
17517f5f010bSBen Gras 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
17527f5f010bSBen Gras 		cp = str + 2;
17537f5f010bSBen Gras 		val = strtol(cp, &ep, 16);
17547f5f010bSBen Gras 	} else
17557f5f010bSBen Gras 		val = strtol(str, &ep, 10);
17567f5f010bSBen Gras 	if (errno || str[0] == '\0' || *ep != '\0')
17577f5f010bSBen Gras 		errx(1, "\"%s\" bad value for %s", str, what);
17587f5f010bSBen Gras 	if (val < mi && mi >= 0) {
17597f5f010bSBen Gras 		if (mi == 0)
17607f5f010bSBen Gras 			errx(1, "%s must be >= %d", what, mi);
17617f5f010bSBen Gras 		else
17627f5f010bSBen Gras 			errx(1, "%s must be > %d", what, mi - 1);
17637f5f010bSBen Gras 	}
17647f5f010bSBen Gras 	if (val > ma && ma >= 0)
17657f5f010bSBen Gras 		errx(1, "%s must be <= %d", what, ma);
17667f5f010bSBen Gras 	return (int)val;
17677f5f010bSBen Gras }
17687f5f010bSBen Gras 
17697f5f010bSBen Gras __dead void
usage(void)17707f5f010bSBen Gras usage(void)
17717f5f010bSBen Gras {
17727f5f010bSBen Gras 	extern char version[];
17737f5f010bSBen Gras 
17747f5f010bSBen Gras 	Fprintf(stderr, "Version %s\n", version);
17757f5f010bSBen Gras 	Fprintf(stderr, "Usage: %s [-adDFPIlMnrvx] [-g gateway] [-i iface] \
17767f5f010bSBen Gras [-f first_ttl]\n\t[-m max_ttl] [-p port] [-q nqueries] [-s src_addr] [-t tos]\n\t\
17777f5f010bSBen Gras [-w waittime] [-z pausemsecs] [-A as_server] host [packetlen]\n",
17787f5f010bSBen Gras 	    getprogname());
17797f5f010bSBen Gras 	exit(1);
17807f5f010bSBen Gras }
17817f5f010bSBen Gras 
17827f5f010bSBen Gras /*
17837f5f010bSBen Gras  * Received ICMP unreachable (fragmentation required and DF set).
17847f5f010bSBen Gras  * If the ICMP error was from a "new" router, it'll contain the next-hop
17857f5f010bSBen Gras  * MTU that we should use next.  Otherwise we'll just keep going in the
17867f5f010bSBen Gras  * mtus[] table, trying until we hit a valid MTU.
17877f5f010bSBen Gras  */
17887f5f010bSBen Gras 
17897f5f010bSBen Gras 
17907f5f010bSBen Gras void
frag_err()17917f5f010bSBen Gras frag_err()
17927f5f010bSBen Gras {
17937f5f010bSBen Gras         int i;
17947f5f010bSBen Gras 
17957f5f010bSBen Gras         if (nextmtu > 0 && nextmtu < packlen) {
17967f5f010bSBen Gras                 Printf("\nfragmentation required and DF set, "
17977f5f010bSBen Gras 		     "next hop MTU = %d\n",
17987f5f010bSBen Gras                         nextmtu);
17997f5f010bSBen Gras                 packlen = nextmtu;
18007f5f010bSBen Gras                 for (i = 0; mtus[i] > 0; i++) {
18017f5f010bSBen Gras                         if (mtus[i] < nextmtu) {
18027f5f010bSBen Gras                                 mtuptr = &mtus[i];    /* next one to try */
18037f5f010bSBen Gras                                 break;
18047f5f010bSBen Gras                         }
18057f5f010bSBen Gras                 }
18067f5f010bSBen Gras         } else {
18077f5f010bSBen Gras                 Printf("\nfragmentation required and DF set. ");
18087f5f010bSBen Gras 		if (nextmtu)
18097f5f010bSBen Gras 			Printf("\nBogus next hop MTU = %d > last MTU = %d. ",
18107f5f010bSBen Gras 			    nextmtu, packlen);
18117f5f010bSBen Gras                 packlen = *mtuptr++;
18127f5f010bSBen Gras 		Printf("Trying new MTU = %d\n", packlen);
18137f5f010bSBen Gras         }
18147f5f010bSBen Gras 	resize_packet();
18157f5f010bSBen Gras }
18167f5f010bSBen Gras 
18177f5f010bSBen Gras int
find_local_ip(struct sockaddr_in * from,struct sockaddr_in * to)18187f5f010bSBen Gras find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
18197f5f010bSBen Gras {
18207f5f010bSBen Gras 	int sock;
18217f5f010bSBen Gras 	struct sockaddr_in help;
18227f5f010bSBen Gras 	socklen_t help_len;
18237f5f010bSBen Gras 
18247f5f010bSBen Gras 	sock = prog_socket(AF_INET, SOCK_DGRAM, 0);
18257f5f010bSBen Gras 	if (sock < 0) return 0;
18267f5f010bSBen Gras 
18277f5f010bSBen Gras 	help.sin_family = AF_INET;
18287f5f010bSBen Gras 	/*
18297f5f010bSBen Gras 	 * At this point the port number doesn't matter
18307f5f010bSBen Gras 	 * since it only has to be greater than zero.
18317f5f010bSBen Gras 	 */
18327f5f010bSBen Gras 	help.sin_port = 42;
18337f5f010bSBen Gras 	help.sin_addr.s_addr = to->sin_addr.s_addr;
18347f5f010bSBen Gras 	if (prog_connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
18357f5f010bSBen Gras 		(void)prog_close(sock);
18367f5f010bSBen Gras 		return 0;
18377f5f010bSBen Gras 	}
18387f5f010bSBen Gras 
18397f5f010bSBen Gras 	help_len = sizeof(help);
18407f5f010bSBen Gras 	if (prog_getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
18417f5f010bSBen Gras 	    help_len != sizeof(help) ||
18427f5f010bSBen Gras 	    help.sin_addr.s_addr == INADDR_ANY) {
18437f5f010bSBen Gras 		(void)prog_close(sock);
18447f5f010bSBen Gras 		return 0;
18457f5f010bSBen Gras 	}
18467f5f010bSBen Gras 
18477f5f010bSBen Gras 	(void)prog_close(sock);
18487f5f010bSBen Gras 	setsin(from, help.sin_addr.s_addr);
18497f5f010bSBen Gras 	return 1;
18507f5f010bSBen Gras }
18517f5f010bSBen Gras 
18527f5f010bSBen Gras #ifdef IPSEC
18537f5f010bSBen Gras #ifdef IPSEC_POLICY_IPSEC
18547f5f010bSBen Gras static int
setpolicy(int so,const char * policy)18557f5f010bSBen Gras setpolicy(int so, const char *policy)
18567f5f010bSBen Gras {
18577f5f010bSBen Gras 	char *buf;
18587f5f010bSBen Gras 
18597f5f010bSBen Gras 	buf = ipsec_set_policy(policy, strlen(policy));
18607f5f010bSBen Gras 	if (buf == NULL) {
18617f5f010bSBen Gras 		warnx("%s", ipsec_strerror());
18627f5f010bSBen Gras 		return -1;
18637f5f010bSBen Gras 	}
18647f5f010bSBen Gras 	(void)prog_setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
18657f5f010bSBen Gras 		buf, ipsec_get_policylen(buf));
18667f5f010bSBen Gras 
18677f5f010bSBen Gras 	free(buf);
18687f5f010bSBen Gras 
18697f5f010bSBen Gras 	return 0;
18707f5f010bSBen Gras }
18717f5f010bSBen Gras #endif
18727f5f010bSBen Gras #endif
18737f5f010bSBen Gras 
1874