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