10382be72SJeroen Ruigrok/asmodai /*	$OpenBSD: traceroute.c,v 1.61 2004/01/26 18:23:51 deraadt Exp $	*/
20382be72SJeroen Ruigrok/asmodai /*	$NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft Exp $	*/
30382be72SJeroen Ruigrok/asmodai 
40382be72SJeroen Ruigrok/asmodai /*-
50382be72SJeroen Ruigrok/asmodai  * Copyright (c) 1990, 1993
60382be72SJeroen Ruigrok/asmodai  *	The Regents of the University of California.  All rights reserved.
70382be72SJeroen Ruigrok/asmodai  *
80382be72SJeroen Ruigrok/asmodai  * This code is derived from software contributed to Berkeley by
90382be72SJeroen Ruigrok/asmodai  * Van Jacobson.
100382be72SJeroen Ruigrok/asmodai  *
110382be72SJeroen Ruigrok/asmodai  * Redistribution and use in source and binary forms, with or without
120382be72SJeroen Ruigrok/asmodai  * modification, are permitted provided that the following conditions
130382be72SJeroen Ruigrok/asmodai  * are met:
140382be72SJeroen Ruigrok/asmodai  * 1. Redistributions of source code must retain the above copyright
150382be72SJeroen Ruigrok/asmodai  *    notice, this list of conditions and the following disclaimer.
160382be72SJeroen Ruigrok/asmodai  * 2. Redistributions in binary form must reproduce the above copyright
170382be72SJeroen Ruigrok/asmodai  *    notice, this list of conditions and the following disclaimer in the
180382be72SJeroen Ruigrok/asmodai  *    documentation and/or other materials provided with the distribution.
190382be72SJeroen Ruigrok/asmodai  * 3. Neither the name of the University nor the names of its contributors
200382be72SJeroen Ruigrok/asmodai  *    may be used to endorse or promote products derived from this software
210382be72SJeroen Ruigrok/asmodai  *    without specific prior written permission.
220382be72SJeroen Ruigrok/asmodai  *
230382be72SJeroen Ruigrok/asmodai  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
240382be72SJeroen Ruigrok/asmodai  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
250382be72SJeroen Ruigrok/asmodai  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
260382be72SJeroen Ruigrok/asmodai  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
270382be72SJeroen Ruigrok/asmodai  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
280382be72SJeroen Ruigrok/asmodai  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
290382be72SJeroen Ruigrok/asmodai  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
300382be72SJeroen Ruigrok/asmodai  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
310382be72SJeroen Ruigrok/asmodai  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
320382be72SJeroen Ruigrok/asmodai  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
330382be72SJeroen Ruigrok/asmodai  * SUCH DAMAGE.
340382be72SJeroen Ruigrok/asmodai  *
359dadf159SEirik Nygaard  * @(#)traceroute.c	8.1 (Berkeley) 6/6/93
360382be72SJeroen Ruigrok/asmodai  */
370382be72SJeroen Ruigrok/asmodai 
380382be72SJeroen Ruigrok/asmodai /*
390382be72SJeroen Ruigrok/asmodai  * traceroute host  - trace the route ip packets follow going to "host".
400382be72SJeroen Ruigrok/asmodai  *
410382be72SJeroen Ruigrok/asmodai  * Attempt to trace the route an ip packet would follow to some
420382be72SJeroen Ruigrok/asmodai  * internet host.  We find out intermediate hops by launching probe
430382be72SJeroen Ruigrok/asmodai  * packets with a small ttl (time to live) then listening for an
440382be72SJeroen Ruigrok/asmodai  * icmp "time exceeded" reply from a gateway.  We start our probes
450382be72SJeroen Ruigrok/asmodai  * with a ttl of one and increase by one until we get an icmp "port
460382be72SJeroen Ruigrok/asmodai  * unreachable" (which means we got to "host") or hit a max (which
470382be72SJeroen Ruigrok/asmodai  * defaults to 64 hops & can be changed with the -m flag).  Three
480382be72SJeroen Ruigrok/asmodai  * probes (change with -q flag) are sent at each ttl setting and a
490382be72SJeroen Ruigrok/asmodai  * line is printed showing the ttl, address of the gateway and
500382be72SJeroen Ruigrok/asmodai  * round trip time of each probe.  If the probe answers come from
510382be72SJeroen Ruigrok/asmodai  * different gateways, the address of each responding system will
520382be72SJeroen Ruigrok/asmodai  * be printed.  If there is no response within a 5 sec. timeout
530382be72SJeroen Ruigrok/asmodai  * interval (changed with the -w flag), a "*" is printed for that
540382be72SJeroen Ruigrok/asmodai  * probe.
550382be72SJeroen Ruigrok/asmodai  *
560382be72SJeroen Ruigrok/asmodai  * Probe packets are UDP format.  We don't want the destination
570382be72SJeroen Ruigrok/asmodai  * host to process them so the destination port is set to an
580382be72SJeroen Ruigrok/asmodai  * unlikely value (if some clod on the destination is using that
590382be72SJeroen Ruigrok/asmodai  * value, it can be changed with the -p flag).
600382be72SJeroen Ruigrok/asmodai  *
610382be72SJeroen Ruigrok/asmodai  * A sample use might be:
620382be72SJeroen Ruigrok/asmodai  *
630382be72SJeroen Ruigrok/asmodai  *     [yak 71]% traceroute nis.nsf.net.
640382be72SJeroen Ruigrok/asmodai  *     traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
650382be72SJeroen Ruigrok/asmodai  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
660382be72SJeroen Ruigrok/asmodai  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
670382be72SJeroen Ruigrok/asmodai  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
680382be72SJeroen Ruigrok/asmodai  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
690382be72SJeroen Ruigrok/asmodai  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
700382be72SJeroen Ruigrok/asmodai  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
710382be72SJeroen Ruigrok/asmodai  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
720382be72SJeroen Ruigrok/asmodai  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
730382be72SJeroen Ruigrok/asmodai  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
740382be72SJeroen Ruigrok/asmodai  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
750382be72SJeroen Ruigrok/asmodai  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
760382be72SJeroen Ruigrok/asmodai  *
770382be72SJeroen Ruigrok/asmodai  * Note that lines 2 & 3 are the same.  This is due to a buggy
780382be72SJeroen Ruigrok/asmodai  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
790382be72SJeroen Ruigrok/asmodai  * packets with a zero ttl.
800382be72SJeroen Ruigrok/asmodai  *
810382be72SJeroen Ruigrok/asmodai  * A more interesting example is:
820382be72SJeroen Ruigrok/asmodai  *
830382be72SJeroen Ruigrok/asmodai  *     [yak 72]% traceroute allspice.lcs.mit.edu.
840382be72SJeroen Ruigrok/asmodai  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
850382be72SJeroen Ruigrok/asmodai  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
860382be72SJeroen Ruigrok/asmodai  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
870382be72SJeroen Ruigrok/asmodai  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
880382be72SJeroen Ruigrok/asmodai  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
890382be72SJeroen Ruigrok/asmodai  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
900382be72SJeroen Ruigrok/asmodai  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
910382be72SJeroen Ruigrok/asmodai  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
920382be72SJeroen Ruigrok/asmodai  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
930382be72SJeroen Ruigrok/asmodai  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
940382be72SJeroen Ruigrok/asmodai  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
950382be72SJeroen Ruigrok/asmodai  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
960382be72SJeroen Ruigrok/asmodai  *     12  * * *
970382be72SJeroen Ruigrok/asmodai  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
980382be72SJeroen Ruigrok/asmodai  *     14  * * *
990382be72SJeroen Ruigrok/asmodai  *     15  * * *
1000382be72SJeroen Ruigrok/asmodai  *     16  * * *
1010382be72SJeroen Ruigrok/asmodai  *     17  * * *
1020382be72SJeroen Ruigrok/asmodai  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
1030382be72SJeroen Ruigrok/asmodai  *
1040382be72SJeroen Ruigrok/asmodai  * (I start to see why I'm having so much trouble with mail to
1050382be72SJeroen Ruigrok/asmodai  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
1060382be72SJeroen Ruigrok/asmodai  * either don't send ICMP "time exceeded" messages or send them
1070382be72SJeroen Ruigrok/asmodai  * with a ttl too small to reach us.  14 - 17 are running the
1080382be72SJeroen Ruigrok/asmodai  * MIT C Gateway code that doesn't send "time exceeded"s.  God
1090382be72SJeroen Ruigrok/asmodai  * only knows what's going on with 12.
1100382be72SJeroen Ruigrok/asmodai  *
1110382be72SJeroen Ruigrok/asmodai  * The silent gateway 12 in the above may be the result of a bug in
1120382be72SJeroen Ruigrok/asmodai  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
1130382be72SJeroen Ruigrok/asmodai  * sends an unreachable message using whatever ttl remains in the
1140382be72SJeroen Ruigrok/asmodai  * original datagram.  Since, for gateways, the remaining ttl is
1150382be72SJeroen Ruigrok/asmodai  * zero, the icmp "time exceeded" is guaranteed to not make it back
1160382be72SJeroen Ruigrok/asmodai  * to us.  The behavior of this bug is slightly more interesting
1170382be72SJeroen Ruigrok/asmodai  * when it appears on the destination system:
1180382be72SJeroen Ruigrok/asmodai  *
1190382be72SJeroen Ruigrok/asmodai  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
1200382be72SJeroen Ruigrok/asmodai  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
1210382be72SJeroen Ruigrok/asmodai  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
1220382be72SJeroen Ruigrok/asmodai  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
1230382be72SJeroen Ruigrok/asmodai  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
1240382be72SJeroen Ruigrok/asmodai  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
1250382be72SJeroen Ruigrok/asmodai  *      7  * * *
1260382be72SJeroen Ruigrok/asmodai  *      8  * * *
1270382be72SJeroen Ruigrok/asmodai  *      9  * * *
1280382be72SJeroen Ruigrok/asmodai  *     10  * * *
1290382be72SJeroen Ruigrok/asmodai  *     11  * * *
1300382be72SJeroen Ruigrok/asmodai  *     12  * * *
1310382be72SJeroen Ruigrok/asmodai  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
1320382be72SJeroen Ruigrok/asmodai  *
1330382be72SJeroen Ruigrok/asmodai  * Notice that there are 12 "gateways" (13 is the final
1340382be72SJeroen Ruigrok/asmodai  * destination) and exactly the last half of them are "missing".
1350382be72SJeroen Ruigrok/asmodai  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
1360382be72SJeroen Ruigrok/asmodai  * is using the ttl from our arriving datagram as the ttl in its
1370382be72SJeroen Ruigrok/asmodai  * icmp reply.  So, the reply will time out on the return path
1380382be72SJeroen Ruigrok/asmodai  * (with no notice sent to anyone since icmp's aren't sent for
1390382be72SJeroen Ruigrok/asmodai  * icmp's) until we probe with a ttl that's at least twice the path
1400382be72SJeroen Ruigrok/asmodai  * length.  I.e., rip is really only 7 hops away.  A reply that
1410382be72SJeroen Ruigrok/asmodai  * returns with a ttl of 1 is a clue this problem exists.
1420382be72SJeroen Ruigrok/asmodai  * Traceroute prints a "!" after the time if the ttl is <= 1.
1430382be72SJeroen Ruigrok/asmodai  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
1440382be72SJeroen Ruigrok/asmodai  * non-standard (HPUX) software, expect to see this problem
1450382be72SJeroen Ruigrok/asmodai  * frequently and/or take care picking the target host of your
1460382be72SJeroen Ruigrok/asmodai  * probes.
1470382be72SJeroen Ruigrok/asmodai  *
1480382be72SJeroen Ruigrok/asmodai  * Other possible annotations after the time are !H, !N, !P (got a host,
1490382be72SJeroen Ruigrok/asmodai  * network or protocol unreachable, respectively), !S or !F (source
1500382be72SJeroen Ruigrok/asmodai  * route failed or fragmentation needed -- neither of these should
1510382be72SJeroen Ruigrok/asmodai  * ever occur and the associated gateway is busted if you see one).  If
1520382be72SJeroen Ruigrok/asmodai  * almost all the probes result in some kind of unreachable, traceroute
1530382be72SJeroen Ruigrok/asmodai  * will give up and exit.
1540382be72SJeroen Ruigrok/asmodai  *
1550382be72SJeroen Ruigrok/asmodai  * Notes
1560382be72SJeroen Ruigrok/asmodai  * -----
1570382be72SJeroen Ruigrok/asmodai  * This program must be run by root or be setuid.  (I suggest that
1580382be72SJeroen Ruigrok/asmodai  * you *don't* make it setuid -- casual use could result in a lot
1590382be72SJeroen Ruigrok/asmodai  * of unnecessary traffic on our poor, congested nets.)
1600382be72SJeroen Ruigrok/asmodai  *
1610382be72SJeroen Ruigrok/asmodai  * This program requires a kernel mod that does not appear in any
1620382be72SJeroen Ruigrok/asmodai  * system available from Berkeley:  A raw ip socket using proto
1630382be72SJeroen Ruigrok/asmodai  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
1640382be72SJeroen Ruigrok/asmodai  * opposed to data to be wrapped in a ip datagram).  See the README
1650382be72SJeroen Ruigrok/asmodai  * file that came with the source to this program for a description
1660382be72SJeroen Ruigrok/asmodai  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
1670382be72SJeroen Ruigrok/asmodai  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
1680382be72SJeroen Ruigrok/asmodai  * MODIFIED TO RUN THIS PROGRAM.
1690382be72SJeroen Ruigrok/asmodai  *
1700382be72SJeroen Ruigrok/asmodai  * The udp port usage may appear bizarre (well, ok, it is bizarre).
1710382be72SJeroen Ruigrok/asmodai  * The problem is that an icmp message only contains 8 bytes of
1720382be72SJeroen Ruigrok/asmodai  * data from the original datagram.  8 bytes is the size of a udp
1730382be72SJeroen Ruigrok/asmodai  * header so, if we want to associate replies with the original
1740382be72SJeroen Ruigrok/asmodai  * datagram, the necessary information must be encoded into the
1750382be72SJeroen Ruigrok/asmodai  * udp header (the ip id could be used but there's no way to
1760382be72SJeroen Ruigrok/asmodai  * interlock with the kernel's assignment of ip id's and, anyway,
1770382be72SJeroen Ruigrok/asmodai  * it would have taken a lot more kernel hacking to allow this
1780382be72SJeroen Ruigrok/asmodai  * code to set the ip id).  So, to allow two or more users to
1790382be72SJeroen Ruigrok/asmodai  * use traceroute simultaneously, we use this task's pid as the
1800382be72SJeroen Ruigrok/asmodai  * source port (the high bit is set to move the port number out
1810382be72SJeroen Ruigrok/asmodai  * of the "likely" range).  To keep track of which probe is being
1820382be72SJeroen Ruigrok/asmodai  * replied to (so times and/or hop counts don't get confused by a
1830382be72SJeroen Ruigrok/asmodai  * reply that was delayed in transit), we increment the destination
1840382be72SJeroen Ruigrok/asmodai  * port number before each probe.
1850382be72SJeroen Ruigrok/asmodai  *
1860382be72SJeroen Ruigrok/asmodai  * Don't use this as a coding example.  I was trying to find a
1870382be72SJeroen Ruigrok/asmodai  * routing problem and this code sort-of popped out after 48 hours
1880382be72SJeroen Ruigrok/asmodai  * without sleep.  I was amazed it ever compiled, much less ran.
1890382be72SJeroen Ruigrok/asmodai  *
1900382be72SJeroen Ruigrok/asmodai  * I stole the idea for this program from Steve Deering.  Since
1910382be72SJeroen Ruigrok/asmodai  * the first release, I've learned that had I attended the right
1920382be72SJeroen Ruigrok/asmodai  * IETF working group meetings, I also could have stolen it from Guy
1930382be72SJeroen Ruigrok/asmodai  * Almes or Matt Mathis.  I don't know (or care) who came up with
1940382be72SJeroen Ruigrok/asmodai  * the idea first.  I envy the originators' perspicacity and I'm
1950382be72SJeroen Ruigrok/asmodai  * glad they didn't keep the idea a secret.
1960382be72SJeroen Ruigrok/asmodai  *
1970382be72SJeroen Ruigrok/asmodai  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
1980382be72SJeroen Ruigrok/asmodai  * enhancements to the original distribution.
1990382be72SJeroen Ruigrok/asmodai  *
2000382be72SJeroen Ruigrok/asmodai  * I've hacked up a round-trip-route version of this that works by
2010382be72SJeroen Ruigrok/asmodai  * sending a loose-source-routed udp datagram through the destination
2020382be72SJeroen Ruigrok/asmodai  * back to yourself.  Unfortunately, SO many gateways botch source
2030382be72SJeroen Ruigrok/asmodai  * routing, the thing is almost worthless.  Maybe one day...
2040382be72SJeroen Ruigrok/asmodai  *
2050382be72SJeroen Ruigrok/asmodai  *  -- Van Jacobson (van@helios.ee.lbl.gov)
2060382be72SJeroen Ruigrok/asmodai  *     Tue Dec 20 03:50:13 PST 1988
2070382be72SJeroen Ruigrok/asmodai  */
2080382be72SJeroen Ruigrok/asmodai 
2090382be72SJeroen Ruigrok/asmodai #include <sys/param.h>
2100382be72SJeroen Ruigrok/asmodai #include <sys/time.h>
2110382be72SJeroen Ruigrok/asmodai #include <sys/socket.h>
2120382be72SJeroen Ruigrok/asmodai #include <sys/file.h>
2130382be72SJeroen Ruigrok/asmodai #include <sys/ioctl.h>
2140382be72SJeroen Ruigrok/asmodai #include <sys/sysctl.h>
2150382be72SJeroen Ruigrok/asmodai 
2160382be72SJeroen Ruigrok/asmodai #include <netinet/in_systm.h>
2170382be72SJeroen Ruigrok/asmodai #include <netinet/in.h>
2180382be72SJeroen Ruigrok/asmodai #include <netinet/ip.h>
2190382be72SJeroen Ruigrok/asmodai #include <netinet/ip_icmp.h>
2200382be72SJeroen Ruigrok/asmodai #include <netinet/ip_var.h>
2210382be72SJeroen Ruigrok/asmodai #include <netinet/udp.h>
2220382be72SJeroen Ruigrok/asmodai 
2230382be72SJeroen Ruigrok/asmodai #include <arpa/inet.h>
2240382be72SJeroen Ruigrok/asmodai 
2250382be72SJeroen Ruigrok/asmodai #include <ctype.h>
2260382be72SJeroen Ruigrok/asmodai #include <err.h>
2270382be72SJeroen Ruigrok/asmodai #include <errno.h>
2280382be72SJeroen Ruigrok/asmodai #include <netdb.h>
2290382be72SJeroen Ruigrok/asmodai #include <stdio.h>
2300382be72SJeroen Ruigrok/asmodai #include <stdlib.h>
2310382be72SJeroen Ruigrok/asmodai #include <string.h>
2320382be72SJeroen Ruigrok/asmodai #include <unistd.h>
2330382be72SJeroen Ruigrok/asmodai 
2340382be72SJeroen Ruigrok/asmodai #define	MAX_LSRR	((MAX_IPOPTLEN - 4) / 4)
2350382be72SJeroen Ruigrok/asmodai 
2360382be72SJeroen Ruigrok/asmodai /*
2370382be72SJeroen Ruigrok/asmodai  * Format of the data in a (udp) probe packet.
2380382be72SJeroen Ruigrok/asmodai  */
2390382be72SJeroen Ruigrok/asmodai struct packetdata {
2400382be72SJeroen Ruigrok/asmodai 	u_char seq;		/* sequence number of this packet */
2410382be72SJeroen Ruigrok/asmodai 	u_int8_t ttl;		/* ttl packet left with */
2420382be72SJeroen Ruigrok/asmodai 	u_int32_t sec;		/* time packet left */
2430382be72SJeroen Ruigrok/asmodai 	u_int32_t usec;
2440382be72SJeroen Ruigrok/asmodai };
2450382be72SJeroen Ruigrok/asmodai 
24646877004SHasso Tepper /*
247dea1b2d2SHasso Tepper  * Support for ICMP extensions - RFC4950.
24846877004SHasso Tepper  */
24946877004SHasso Tepper #define ICMP_EXT_OFFSET  8 + 128 /* ICMP type, code, checksum (unused)
25046877004SHasso Tepper 				  * + original datagram */
25146877004SHasso Tepper #define ICMP_EXT_VERSION 2
25246877004SHasso Tepper 
25346877004SHasso Tepper /* ICMP Extension Header according to RFC4884. */
25446877004SHasso Tepper #define EXT_VERSION(x)	(((x) & 0xf0000000) >> 28)
25546877004SHasso Tepper #define EXT_CHECKSUM(x)	((x) & 0x0000ffff)
25646877004SHasso Tepper 
25746877004SHasso Tepper /*
25846877004SHasso Tepper  * ICMP extensions, object header
25946877004SHasso Tepper  */
26046877004SHasso Tepper struct icmp_ext_obj_hdr {
26146877004SHasso Tepper 	u_short length;
26246877004SHasso Tepper 	u_char  class_num;
26346877004SHasso Tepper #define MPLS_STACK_ENTRY_CLASS 1
26446877004SHasso Tepper 	u_char  c_type;
26546877004SHasso Tepper #define MPLS_STACK_ENTRY_C_TYPE 1
26646877004SHasso Tepper };
26746877004SHasso Tepper 
26846877004SHasso Tepper /* MPLS Label Stack Object. */
26946877004SHasso Tepper #define MPLS_LABEL(x)   (((x) & 0xfffff000) >> 12)
27046877004SHasso Tepper #define MPLS_EXP(x)     (((x) & 0x00000e00) >> 9)
27146877004SHasso Tepper #define MPLS_STACK(x)   (((x) & 0x00000100) >> 8)
27246877004SHasso Tepper #define MPLS_TTL(x)     ((x) & 0x000000ff)
27346877004SHasso Tepper 
274d6410035SSascha Wildner static struct in_addr gateway[MAX_LSRR + 1];
275d6410035SSascha Wildner static int lsrrlen = 0;
276d6410035SSascha Wildner static int32_t sec_perturb;
277d6410035SSascha Wildner static int32_t usec_perturb;
2780382be72SJeroen Ruigrok/asmodai 
279d6410035SSascha Wildner static u_char packet[512], *outpacket;	/* last inbound (icmp) packet */
2800382be72SJeroen Ruigrok/asmodai 
281d6410035SSascha Wildner static void decode_extensions(unsigned char *, int);
282d6410035SSascha Wildner static void dump_packet(void);
283d6410035SSascha Wildner static int wait_for_reply(int, struct sockaddr_in *, struct timeval *);
284d6410035SSascha Wildner static void send_probe(int, u_int8_t, int, struct sockaddr_in *);
285d6410035SSascha Wildner static int packet_ok(u_char *, int, struct sockaddr_in *, int, int);
286d6410035SSascha Wildner static const char *pr_type(u_int8_t);
287d6410035SSascha Wildner static void print(u_char *, int, struct sockaddr_in *);
288d6410035SSascha Wildner static char *inetname(struct in_addr);
289d6410035SSascha Wildner static u_short in_cksum(u_short *, int);
290fe08e20dSSascha Wildner static void usage(void) __dead2;
2910382be72SJeroen Ruigrok/asmodai 
292d6410035SSascha Wildner static int s;			/* receive (icmp) socket file descriptor */
293d6410035SSascha Wildner static int sndsock;		/* send (udp) socket file descriptor */
2940382be72SJeroen Ruigrok/asmodai 
295d6410035SSascha Wildner static int datalen;		/* How much data */
296d6410035SSascha Wildner static int headerlen;		/* How long packet's header is */
2970382be72SJeroen Ruigrok/asmodai 
298d6410035SSascha Wildner static char *source = NULL;
299d6410035SSascha Wildner static char *hostname;
3000382be72SJeroen Ruigrok/asmodai 
301d6410035SSascha Wildner static int nprobes = 3;
302d6410035SSascha Wildner static u_int8_t max_ttl = IPDEFTTL;
303d6410035SSascha Wildner static u_int8_t first_ttl = 1;
304d6410035SSascha Wildner static u_short ident;
305d6410035SSascha Wildner static u_short port = 32768+666; /* start udp dest port # for probe packets */
306d6410035SSascha Wildner static u_char	proto = IPPROTO_UDP;
307d6410035SSascha Wildner static u_int8_t  icmp_type = ICMP_ECHO; /* default ICMP code/type */
308d6410035SSascha Wildner static u_char  icmp_code = 0;
309d6410035SSascha Wildner static int options;		/* socket options */
310d6410035SSascha Wildner static int verbose;
311d6410035SSascha Wildner static int waittime = 5;	/* time to wait for response (in seconds) */
312d6410035SSascha Wildner static int nflag;		/* print addresses numerically */
313d6410035SSascha Wildner static int dump;
314d6410035SSascha Wildner static int Mflag;		/* show MPLS labels if any */
3150382be72SJeroen Ruigrok/asmodai 
3160382be72SJeroen Ruigrok/asmodai int
main(int argc,char * argv[])3170382be72SJeroen Ruigrok/asmodai main(int argc, char *argv[])
3180382be72SJeroen Ruigrok/asmodai {
3190382be72SJeroen Ruigrok/asmodai 	int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
3200382be72SJeroen Ruigrok/asmodai 	int ttl_flag = 0, incflag = 1, protoset = 0, sump = 0;
3210382be72SJeroen Ruigrok/asmodai 	int ch, i, lsrr = 0, on = 1, probe, seq = 0, tos = 0;
3220382be72SJeroen Ruigrok/asmodai 	size_t size = sizeof(max_ttl);
3230382be72SJeroen Ruigrok/asmodai 	struct sockaddr_in from, to;
3240382be72SJeroen Ruigrok/asmodai 	struct hostent *hp;
3250382be72SJeroen Ruigrok/asmodai 	u_int32_t tmprnd;
3260382be72SJeroen Ruigrok/asmodai 	struct ip *ip;
3270382be72SJeroen Ruigrok/asmodai 	u_int8_t ttl;
3280382be72SJeroen Ruigrok/asmodai 	char *ep;
3290382be72SJeroen Ruigrok/asmodai 	long l;
3300382be72SJeroen Ruigrok/asmodai 
3310382be72SJeroen Ruigrok/asmodai 	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
3320382be72SJeroen Ruigrok/asmodai 		err(5, "icmp socket");
3330382be72SJeroen Ruigrok/asmodai 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
3340382be72SJeroen Ruigrok/asmodai 		err(5, "raw socket");
3350382be72SJeroen Ruigrok/asmodai 
3360382be72SJeroen Ruigrok/asmodai 	/* revoke privs */
3370382be72SJeroen Ruigrok/asmodai 	seteuid(getuid());
3380382be72SJeroen Ruigrok/asmodai 	setuid(getuid());
3390382be72SJeroen Ruigrok/asmodai 
340*e62ef63cSSascha Wildner 	sysctl(mib, NELEM(mib), &max_ttl, &size, NULL, 0);
3410382be72SJeroen Ruigrok/asmodai 
34246877004SHasso Tepper 	while ((ch = getopt(argc, argv, "SDIdg:f:m:np:q:rs:t:w:vlP:cM")) != -1)
3430382be72SJeroen Ruigrok/asmodai 		switch (ch) {
3440382be72SJeroen Ruigrok/asmodai 		case 'S':
3450382be72SJeroen Ruigrok/asmodai 			sump = 1;
3460382be72SJeroen Ruigrok/asmodai 			break;
3470382be72SJeroen Ruigrok/asmodai 		case 'f':
3480382be72SJeroen Ruigrok/asmodai 			errno = 0;
3490382be72SJeroen Ruigrok/asmodai 			ep = NULL;
3500382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
3510382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l < 1 || l > max_ttl)
3520382be72SJeroen Ruigrok/asmodai 				errx(1, "min ttl must be 1 to %u.", max_ttl);
3530382be72SJeroen Ruigrok/asmodai 			first_ttl = (u_int8_t)l;
3540382be72SJeroen Ruigrok/asmodai 			break;
3550382be72SJeroen Ruigrok/asmodai 		case 'c':
3560382be72SJeroen Ruigrok/asmodai 			incflag = 0;
3570382be72SJeroen Ruigrok/asmodai 			break;
3580382be72SJeroen Ruigrok/asmodai 		case 'd':
3590382be72SJeroen Ruigrok/asmodai 			options |= SO_DEBUG;
3600382be72SJeroen Ruigrok/asmodai 			break;
3610382be72SJeroen Ruigrok/asmodai 		case 'D':
3620382be72SJeroen Ruigrok/asmodai 			dump = 1;
3630382be72SJeroen Ruigrok/asmodai 			break;
3640382be72SJeroen Ruigrok/asmodai 		case 'g':
3650382be72SJeroen Ruigrok/asmodai 			if (lsrr >= MAX_LSRR)
3660382be72SJeroen Ruigrok/asmodai 				errx(1, "too many gateways; max %d", MAX_LSRR);
3670382be72SJeroen Ruigrok/asmodai 			if (inet_aton(optarg, &gateway[lsrr]) == 0) {
3680382be72SJeroen Ruigrok/asmodai 				hp = gethostbyname(optarg);
369678e8cc6SSascha Wildner 				if (hp == NULL)
3700382be72SJeroen Ruigrok/asmodai 					errx(1, "unknown host %s", optarg);
3710382be72SJeroen Ruigrok/asmodai 				memcpy(&gateway[lsrr], hp->h_addr, hp->h_length);
3720382be72SJeroen Ruigrok/asmodai 			}
3730382be72SJeroen Ruigrok/asmodai 			if (++lsrr == 1)
3740382be72SJeroen Ruigrok/asmodai 				lsrrlen = 4;
3750382be72SJeroen Ruigrok/asmodai 			lsrrlen += 4;
3760382be72SJeroen Ruigrok/asmodai 			break;
3770382be72SJeroen Ruigrok/asmodai 		case 'I':
3780382be72SJeroen Ruigrok/asmodai 			if (protoset)
3790382be72SJeroen Ruigrok/asmodai 				errx(1, "protocol already set with -P");
3800382be72SJeroen Ruigrok/asmodai 			protoset = 1;
3810382be72SJeroen Ruigrok/asmodai 			proto = IPPROTO_ICMP;
3820382be72SJeroen Ruigrok/asmodai 			break;
3830382be72SJeroen Ruigrok/asmodai 		case 'l':
3840382be72SJeroen Ruigrok/asmodai 			ttl_flag++;
3850382be72SJeroen Ruigrok/asmodai 			break;
3860382be72SJeroen Ruigrok/asmodai 		case 'm':
3870382be72SJeroen Ruigrok/asmodai 			errno = 0;
3880382be72SJeroen Ruigrok/asmodai 			ep = NULL;
3890382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
3900382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l < first_ttl ||
3910382be72SJeroen Ruigrok/asmodai 			    l > MAXTTL)
3920382be72SJeroen Ruigrok/asmodai 				errx(1, "max ttl must be %u to %u.", first_ttl,
3930382be72SJeroen Ruigrok/asmodai 				    MAXTTL);
3940382be72SJeroen Ruigrok/asmodai 			max_ttl = (u_int8_t)l;
3950382be72SJeroen Ruigrok/asmodai 			break;
39646877004SHasso Tepper 		case 'M':
39746877004SHasso Tepper 			Mflag = 1;
39846877004SHasso Tepper 			break;
3990382be72SJeroen Ruigrok/asmodai 		case 'n':
4000382be72SJeroen Ruigrok/asmodai 			nflag++;
4010382be72SJeroen Ruigrok/asmodai 			break;
4020382be72SJeroen Ruigrok/asmodai 		case 'p':
4030382be72SJeroen Ruigrok/asmodai 			errno = 0;
4040382be72SJeroen Ruigrok/asmodai 			ep = NULL;
4050382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
4060382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l <= 0 || l >= 65536)
4070382be72SJeroen Ruigrok/asmodai 				errx(1, "port must be >0, <65536.");
4080382be72SJeroen Ruigrok/asmodai 			port = (int)l;
4090382be72SJeroen Ruigrok/asmodai 			break;
4100382be72SJeroen Ruigrok/asmodai 		case 'P':
4110382be72SJeroen Ruigrok/asmodai 			if (protoset)
4120382be72SJeroen Ruigrok/asmodai 				errx(1, "protocol already set with -I");
4130382be72SJeroen Ruigrok/asmodai 			protoset = 1;
4140382be72SJeroen Ruigrok/asmodai 			errno = 0;
4150382be72SJeroen Ruigrok/asmodai 			ep = NULL;
4160382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
4170382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l < 1 ||
4180382be72SJeroen Ruigrok/asmodai 			    l >= IPPROTO_MAX) {
4190382be72SJeroen Ruigrok/asmodai 				struct protoent *pent;
4200382be72SJeroen Ruigrok/asmodai 
4210382be72SJeroen Ruigrok/asmodai 				pent = getprotobyname(optarg);
4220382be72SJeroen Ruigrok/asmodai 				if (pent)
4230382be72SJeroen Ruigrok/asmodai 					proto = pent->p_proto;
4240382be72SJeroen Ruigrok/asmodai 				else
4250382be72SJeroen Ruigrok/asmodai 					errx(1, "proto must be >=1, or a name.");
4260382be72SJeroen Ruigrok/asmodai 			} else
4270382be72SJeroen Ruigrok/asmodai 				proto = (int)l;
4280382be72SJeroen Ruigrok/asmodai 			break;
4290382be72SJeroen Ruigrok/asmodai 		case 'q':
4300382be72SJeroen Ruigrok/asmodai 			errno = 0;
4310382be72SJeroen Ruigrok/asmodai 			ep = NULL;
4320382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
4330382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l < 1 || l > INT_MAX)
4340382be72SJeroen Ruigrok/asmodai 				errx(1, "nprobes must be >0.");
4350382be72SJeroen Ruigrok/asmodai 			nprobes = (int)l;
4360382be72SJeroen Ruigrok/asmodai 			break;
4370382be72SJeroen Ruigrok/asmodai 		case 'r':
4380382be72SJeroen Ruigrok/asmodai 			options |= SO_DONTROUTE;
4390382be72SJeroen Ruigrok/asmodai 			break;
4400382be72SJeroen Ruigrok/asmodai 		case 's':
4410382be72SJeroen Ruigrok/asmodai 			/*
4420382be72SJeroen Ruigrok/asmodai 			 * set the ip source address of the outbound
4430382be72SJeroen Ruigrok/asmodai 			 * probe (e.g., on a multi-homed host).
4440382be72SJeroen Ruigrok/asmodai 			 */
4450382be72SJeroen Ruigrok/asmodai 			source = optarg;
4460382be72SJeroen Ruigrok/asmodai 			break;
4470382be72SJeroen Ruigrok/asmodai 		case 't':
4480382be72SJeroen Ruigrok/asmodai 			errno = 0;
4490382be72SJeroen Ruigrok/asmodai 			ep = NULL;
4500382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
4510382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l < 0 || l > 255)
4520382be72SJeroen Ruigrok/asmodai 				errx(1, "tos must be 0 to 255.");
4530382be72SJeroen Ruigrok/asmodai 			tos = (int)l;
4540382be72SJeroen Ruigrok/asmodai 			break;
4550382be72SJeroen Ruigrok/asmodai 		case 'v':
4560382be72SJeroen Ruigrok/asmodai 			verbose++;
4570382be72SJeroen Ruigrok/asmodai 			break;
4580382be72SJeroen Ruigrok/asmodai 		case 'w':
4590382be72SJeroen Ruigrok/asmodai 			errno = 0;
4600382be72SJeroen Ruigrok/asmodai 			ep = NULL;
4610382be72SJeroen Ruigrok/asmodai 			l = strtol(optarg, &ep, 10);
4620382be72SJeroen Ruigrok/asmodai 			if (errno || !*optarg || *ep || l <= 1 || l > INT_MAX)
4630382be72SJeroen Ruigrok/asmodai 				errx(1, "wait must be >1 sec.");
4640382be72SJeroen Ruigrok/asmodai 			waittime = (int)l;
4650382be72SJeroen Ruigrok/asmodai 			break;
4660382be72SJeroen Ruigrok/asmodai 		default:
4670382be72SJeroen Ruigrok/asmodai 			usage();
4680382be72SJeroen Ruigrok/asmodai 		}
4690382be72SJeroen Ruigrok/asmodai 	argc -= optind;
4700382be72SJeroen Ruigrok/asmodai 	argv += optind;
4710382be72SJeroen Ruigrok/asmodai 
4720382be72SJeroen Ruigrok/asmodai 	if (argc < 1)
4730382be72SJeroen Ruigrok/asmodai 		usage();
4740382be72SJeroen Ruigrok/asmodai 
4750382be72SJeroen Ruigrok/asmodai 	setlinebuf (stdout);
4760382be72SJeroen Ruigrok/asmodai 
47771126e33SSascha Wildner 	memset(&to, 0, sizeof(struct sockaddr));
4780382be72SJeroen Ruigrok/asmodai 	to.sin_family = AF_INET;
4790382be72SJeroen Ruigrok/asmodai 	if (inet_aton(*argv, &to.sin_addr) != 0)
4800382be72SJeroen Ruigrok/asmodai 		hostname = *argv;
4810382be72SJeroen Ruigrok/asmodai 	else {
4820382be72SJeroen Ruigrok/asmodai 		hp = gethostbyname(*argv);
483678e8cc6SSascha Wildner 		if (hp == NULL)
4840382be72SJeroen Ruigrok/asmodai 			errx(1, "unknown host %s", *argv);
4850382be72SJeroen Ruigrok/asmodai 		to.sin_family = hp->h_addrtype;
4860382be72SJeroen Ruigrok/asmodai 		memcpy(&to.sin_addr, hp->h_addr, hp->h_length);
4870382be72SJeroen Ruigrok/asmodai 		if ((hostname = strdup(hp->h_name)) == NULL)
4880382be72SJeroen Ruigrok/asmodai 			err(1, "malloc");
4890382be72SJeroen Ruigrok/asmodai 		if (hp->h_addr_list[1] != NULL)
4900382be72SJeroen Ruigrok/asmodai 			warnx("Warning: %s has multiple addresses; using %s",
4910382be72SJeroen Ruigrok/asmodai 			    hostname, inet_ntoa(to.sin_addr));
4920382be72SJeroen Ruigrok/asmodai 	}
4930382be72SJeroen Ruigrok/asmodai 	if (*++argv) {
4940382be72SJeroen Ruigrok/asmodai 		errno = 0;
4950382be72SJeroen Ruigrok/asmodai 		ep = NULL;
4960382be72SJeroen Ruigrok/asmodai 		l = strtol(*argv, &ep, 10);
4970382be72SJeroen Ruigrok/asmodai 		if (errno || !*argv || *ep || l < 0 || l > INT_MAX)
4980382be72SJeroen Ruigrok/asmodai 			errx(1, "datalen out of range");
4990382be72SJeroen Ruigrok/asmodai 		datalen = (int)l;
5000382be72SJeroen Ruigrok/asmodai 	}
5010382be72SJeroen Ruigrok/asmodai 
5020382be72SJeroen Ruigrok/asmodai 	switch (proto) {
5030382be72SJeroen Ruigrok/asmodai 	case IPPROTO_UDP:
5040382be72SJeroen Ruigrok/asmodai 		headerlen = (sizeof(struct ip) + lsrrlen +
5050382be72SJeroen Ruigrok/asmodai 		    sizeof(struct udphdr) + sizeof(struct packetdata));
5060382be72SJeroen Ruigrok/asmodai 		break;
5070382be72SJeroen Ruigrok/asmodai 	case IPPROTO_ICMP:
5080382be72SJeroen Ruigrok/asmodai 		headerlen = (sizeof(struct ip) + lsrrlen +
5090382be72SJeroen Ruigrok/asmodai 		    sizeof(struct icmp) + sizeof(struct packetdata));
5100382be72SJeroen Ruigrok/asmodai 		break;
5110382be72SJeroen Ruigrok/asmodai 	default:
5120382be72SJeroen Ruigrok/asmodai 		headerlen = (sizeof(struct ip) + lsrrlen +
5130382be72SJeroen Ruigrok/asmodai 		    sizeof(struct packetdata));
5140382be72SJeroen Ruigrok/asmodai 	}
5150382be72SJeroen Ruigrok/asmodai 
5160382be72SJeroen Ruigrok/asmodai 	if (datalen < 0 || datalen > IP_MAXPACKET - headerlen)
5170382be72SJeroen Ruigrok/asmodai 		errx(1, "packet size must be 0 to %d.",
5180382be72SJeroen Ruigrok/asmodai 		    IP_MAXPACKET - headerlen);
5190382be72SJeroen Ruigrok/asmodai 
5200382be72SJeroen Ruigrok/asmodai 	datalen += headerlen;
5210382be72SJeroen Ruigrok/asmodai 
5220382be72SJeroen Ruigrok/asmodai 	outpacket = (u_char *)malloc(datalen);
5239dadf159SEirik Nygaard 	if (outpacket == NULL)
5240382be72SJeroen Ruigrok/asmodai 		err(1, "malloc");
52571126e33SSascha Wildner 	memset(outpacket, 0, datalen);
5260382be72SJeroen Ruigrok/asmodai 
5270382be72SJeroen Ruigrok/asmodai 	ip = (struct ip *)outpacket;
5280382be72SJeroen Ruigrok/asmodai 	if (lsrr != 0) {
5290382be72SJeroen Ruigrok/asmodai 		u_char *p = (u_char *)(ip + 1);
5300382be72SJeroen Ruigrok/asmodai 
5310382be72SJeroen Ruigrok/asmodai 		*p++ = IPOPT_NOP;
5320382be72SJeroen Ruigrok/asmodai 		*p++ = IPOPT_LSRR;
5330382be72SJeroen Ruigrok/asmodai 		*p++ = lsrrlen - 1;
5340382be72SJeroen Ruigrok/asmodai 		*p++ = IPOPT_MINOFF;
5350382be72SJeroen Ruigrok/asmodai 		gateway[lsrr] = to.sin_addr;
5360382be72SJeroen Ruigrok/asmodai 		for (i = 1; i <= lsrr; i++) {
5370382be72SJeroen Ruigrok/asmodai 			memcpy(p, &gateway[i], sizeof(struct in_addr));
5380382be72SJeroen Ruigrok/asmodai 			p += sizeof(struct in_addr);
5390382be72SJeroen Ruigrok/asmodai 		}
5400382be72SJeroen Ruigrok/asmodai 		ip->ip_dst = gateway[0];
5410382be72SJeroen Ruigrok/asmodai 	} else
5420382be72SJeroen Ruigrok/asmodai 		ip->ip_dst = to.sin_addr;
5430382be72SJeroen Ruigrok/asmodai 	ip->ip_off = htons(0);
5440382be72SJeroen Ruigrok/asmodai 	ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
5450382be72SJeroen Ruigrok/asmodai 	ip->ip_p = proto;
5460382be72SJeroen Ruigrok/asmodai 	ip->ip_v = IPVERSION;
5470382be72SJeroen Ruigrok/asmodai 	ip->ip_tos = tos;
5480382be72SJeroen Ruigrok/asmodai 
5490382be72SJeroen Ruigrok/asmodai 	ident = (getpid() & 0xffff) | 0x8000;
5500382be72SJeroen Ruigrok/asmodai 	tmprnd = arc4random();
5510382be72SJeroen Ruigrok/asmodai 	sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) :
5520382be72SJeroen Ruigrok/asmodai 	    (tmprnd & 0x7ff);
5530382be72SJeroen Ruigrok/asmodai 	usec_perturb = arc4random();
5540382be72SJeroen Ruigrok/asmodai 
5550382be72SJeroen Ruigrok/asmodai 	if (options & SO_DEBUG)
55671126e33SSascha Wildner 		setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on));
5570382be72SJeroen Ruigrok/asmodai #ifdef SO_SNDBUF
5580382be72SJeroen Ruigrok/asmodai 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
5590382be72SJeroen Ruigrok/asmodai 	    sizeof(datalen)) < 0)
5600382be72SJeroen Ruigrok/asmodai 		err(6, "SO_SNDBUF");
5610382be72SJeroen Ruigrok/asmodai #endif /* SO_SNDBUF */
5620382be72SJeroen Ruigrok/asmodai #ifdef IP_HDRINCL
5630382be72SJeroen Ruigrok/asmodai 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
5640382be72SJeroen Ruigrok/asmodai 	    sizeof(on)) < 0)
5650382be72SJeroen Ruigrok/asmodai 		err(6, "IP_HDRINCL");
5660382be72SJeroen Ruigrok/asmodai #endif /* IP_HDRINCL */
5670382be72SJeroen Ruigrok/asmodai 	if (options & SO_DEBUG)
56871126e33SSascha Wildner 		setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
5690382be72SJeroen Ruigrok/asmodai 		    (char *)&on, sizeof(on));
5700382be72SJeroen Ruigrok/asmodai 	if (options & SO_DONTROUTE)
57171126e33SSascha Wildner 		setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
5720382be72SJeroen Ruigrok/asmodai 		    (char *)&on, sizeof(on));
5730382be72SJeroen Ruigrok/asmodai 
5740382be72SJeroen Ruigrok/asmodai 	if (source) {
57571126e33SSascha Wildner 		memset(&from, 0, sizeof(struct sockaddr));
5760382be72SJeroen Ruigrok/asmodai 		from.sin_family = AF_INET;
5770382be72SJeroen Ruigrok/asmodai 		if (inet_aton(source, &from.sin_addr) == 0)
5780382be72SJeroen Ruigrok/asmodai 			errx(1, "unknown host %s", source);
5790382be72SJeroen Ruigrok/asmodai 		ip->ip_src = from.sin_addr;
5800382be72SJeroen Ruigrok/asmodai 		if (getuid() != 0 &&
5810382be72SJeroen Ruigrok/asmodai 		    (ntohl(from.sin_addr.s_addr) & 0xff000000U) == 0x7f000000U &&
5820382be72SJeroen Ruigrok/asmodai 		    (ntohl(to.sin_addr.s_addr) & 0xff000000U) != 0x7f000000U)
5830382be72SJeroen Ruigrok/asmodai 			errx(1, "source is on 127/8, destination is not");
5840382be72SJeroen Ruigrok/asmodai 
5850382be72SJeroen Ruigrok/asmodai 		if (getuid() &&
5860382be72SJeroen Ruigrok/asmodai 		    bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
5870382be72SJeroen Ruigrok/asmodai 			err(1, "bind");
5880382be72SJeroen Ruigrok/asmodai 	}
5890382be72SJeroen Ruigrok/asmodai 
5900382be72SJeroen Ruigrok/asmodai 	fprintf(stderr, "traceroute to %s (%s)", hostname,
5910382be72SJeroen Ruigrok/asmodai 		inet_ntoa(to.sin_addr));
5920382be72SJeroen Ruigrok/asmodai 	if (source)
5930382be72SJeroen Ruigrok/asmodai 		fprintf(stderr, " from %s", source);
5940382be72SJeroen Ruigrok/asmodai 	fprintf(stderr, ", %u hops max, %d byte packets\n", max_ttl, datalen);
59571126e33SSascha Wildner 	fflush(stderr);
5960382be72SJeroen Ruigrok/asmodai 
5970382be72SJeroen Ruigrok/asmodai 	if (first_ttl > 1)
5980382be72SJeroen Ruigrok/asmodai 		printf("Skipping %u intermediate hops\n", first_ttl - 1);
5990382be72SJeroen Ruigrok/asmodai 
6000382be72SJeroen Ruigrok/asmodai 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
6010382be72SJeroen Ruigrok/asmodai 		int got_there = 0, unreachable = 0, timeout = 0, loss;
6023472506cSHasso Tepper 		int gotlastaddr = 0;
6030382be72SJeroen Ruigrok/asmodai 		in_addr_t lastaddr = 0;
6040382be72SJeroen Ruigrok/asmodai 		quad_t dt;
6050382be72SJeroen Ruigrok/asmodai 
6060382be72SJeroen Ruigrok/asmodai 		printf("%2u ", ttl);
6070382be72SJeroen Ruigrok/asmodai 		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
6080382be72SJeroen Ruigrok/asmodai 			int cc;
6090382be72SJeroen Ruigrok/asmodai 			struct timeval t1, t2;
6100382be72SJeroen Ruigrok/asmodai 			int code;
6110382be72SJeroen Ruigrok/asmodai 
61271126e33SSascha Wildner 			gettimeofday(&t1, NULL);
6130382be72SJeroen Ruigrok/asmodai 			send_probe(++seq, ttl, incflag, &to);
6140382be72SJeroen Ruigrok/asmodai 			while ((cc = wait_for_reply(s, &from, &t1))) {
61571126e33SSascha Wildner 				gettimeofday(&t2, NULL);
6160382be72SJeroen Ruigrok/asmodai 				if (t2.tv_sec - t1.tv_sec > waittime) {
6170382be72SJeroen Ruigrok/asmodai 					cc = 0;
6180382be72SJeroen Ruigrok/asmodai 					break;
6190382be72SJeroen Ruigrok/asmodai 				}
6200382be72SJeroen Ruigrok/asmodai 				i = packet_ok(packet, cc, &from, seq, incflag);
6210382be72SJeroen Ruigrok/asmodai 				/* Skip short packet */
6220382be72SJeroen Ruigrok/asmodai 				if (i == 0)
6230382be72SJeroen Ruigrok/asmodai 					continue;
6243472506cSHasso Tepper 				if (!gotlastaddr ||
6253472506cSHasso Tepper 				    from.sin_addr.s_addr != lastaddr) {
6263472506cSHasso Tepper 					if (gotlastaddr)
6273472506cSHasso Tepper 						printf("\n   ");
6280382be72SJeroen Ruigrok/asmodai 					print(packet, cc, &from);
6290382be72SJeroen Ruigrok/asmodai 					lastaddr = from.sin_addr.s_addr;
6303472506cSHasso Tepper 					++gotlastaddr;
6310382be72SJeroen Ruigrok/asmodai 				}
6320382be72SJeroen Ruigrok/asmodai 				dt = (quad_t)(t2.tv_sec - t1.tv_sec) * 1000000 +
6330382be72SJeroen Ruigrok/asmodai 				    (quad_t)(t2.tv_usec - t1.tv_usec);
6340382be72SJeroen Ruigrok/asmodai 				printf("  %u", (u_int)(dt / 1000));
6350382be72SJeroen Ruigrok/asmodai 				if (dt % 1000)
6360382be72SJeroen Ruigrok/asmodai 					printf(".%u", (u_int)(dt % 1000));
6370382be72SJeroen Ruigrok/asmodai 				printf(" ms");
6380382be72SJeroen Ruigrok/asmodai 				ip = (struct ip *)packet;
6390382be72SJeroen Ruigrok/asmodai 				if (ttl_flag)
6400382be72SJeroen Ruigrok/asmodai 					printf(" (%u)", ip->ip_ttl);
6410382be72SJeroen Ruigrok/asmodai 				if (i == -2) {
6420382be72SJeroen Ruigrok/asmodai #ifndef ARCHAIC
6430382be72SJeroen Ruigrok/asmodai 					ip = (struct ip *)packet;
6440382be72SJeroen Ruigrok/asmodai 					if (ip->ip_ttl <= 1)
6450382be72SJeroen Ruigrok/asmodai 						printf(" !");
6460382be72SJeroen Ruigrok/asmodai #endif
6470382be72SJeroen Ruigrok/asmodai 					++got_there;
6480382be72SJeroen Ruigrok/asmodai 					break;
6490382be72SJeroen Ruigrok/asmodai 				}
6500382be72SJeroen Ruigrok/asmodai 				/* time exceeded in transit */
6510382be72SJeroen Ruigrok/asmodai 				if (i == -1)
6520382be72SJeroen Ruigrok/asmodai 					break;
6530382be72SJeroen Ruigrok/asmodai 				code = i - 1;
6540382be72SJeroen Ruigrok/asmodai 				switch (code) {
6550382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_PORT:
6560382be72SJeroen Ruigrok/asmodai #ifndef ARCHAIC
6570382be72SJeroen Ruigrok/asmodai 					ip = (struct ip *)packet;
6580382be72SJeroen Ruigrok/asmodai 					if (ip->ip_ttl <= 1)
6590382be72SJeroen Ruigrok/asmodai 						printf(" !");
6600382be72SJeroen Ruigrok/asmodai #endif /* ARCHAIC */
6610382be72SJeroen Ruigrok/asmodai 					++got_there;
6620382be72SJeroen Ruigrok/asmodai 					break;
6630382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_NET:
6640382be72SJeroen Ruigrok/asmodai 					++unreachable;
6650382be72SJeroen Ruigrok/asmodai 					printf(" !N");
6660382be72SJeroen Ruigrok/asmodai 					break;
6670382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_HOST:
6680382be72SJeroen Ruigrok/asmodai 					++unreachable;
6690382be72SJeroen Ruigrok/asmodai 					printf(" !H");
6700382be72SJeroen Ruigrok/asmodai 					break;
6710382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_PROTOCOL:
6720382be72SJeroen Ruigrok/asmodai 					++got_there;
6730382be72SJeroen Ruigrok/asmodai 					printf(" !P");
6740382be72SJeroen Ruigrok/asmodai 					break;
6750382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_NEEDFRAG:
6760382be72SJeroen Ruigrok/asmodai 					++unreachable;
6770382be72SJeroen Ruigrok/asmodai 					printf(" !F");
6780382be72SJeroen Ruigrok/asmodai 					break;
6790382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_SRCFAIL:
6800382be72SJeroen Ruigrok/asmodai 					++unreachable;
6810382be72SJeroen Ruigrok/asmodai 					printf(" !S");
6820382be72SJeroen Ruigrok/asmodai 					break;
6830382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_FILTER_PROHIB:
6840382be72SJeroen Ruigrok/asmodai 					++unreachable;
6850382be72SJeroen Ruigrok/asmodai 					printf(" !X");
6860382be72SJeroen Ruigrok/asmodai 					break;
6870382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_NET_PROHIB: /*misuse*/
6880382be72SJeroen Ruigrok/asmodai 					++unreachable;
6890382be72SJeroen Ruigrok/asmodai 					printf(" !A");
6900382be72SJeroen Ruigrok/asmodai 					break;
6910382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_HOST_PROHIB:
6920382be72SJeroen Ruigrok/asmodai 					++unreachable;
6930382be72SJeroen Ruigrok/asmodai 					printf(" !C");
6940382be72SJeroen Ruigrok/asmodai 					break;
6950382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_NET_UNKNOWN:
6960382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_HOST_UNKNOWN:
6970382be72SJeroen Ruigrok/asmodai 					++unreachable;
6980382be72SJeroen Ruigrok/asmodai 					printf(" !U");
6990382be72SJeroen Ruigrok/asmodai 					break;
7000382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_ISOLATED:
7010382be72SJeroen Ruigrok/asmodai 					++unreachable;
7020382be72SJeroen Ruigrok/asmodai 					printf(" !I");
7030382be72SJeroen Ruigrok/asmodai 					break;
7040382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_TOSNET:
7050382be72SJeroen Ruigrok/asmodai 				case ICMP_UNREACH_TOSHOST:
7060382be72SJeroen Ruigrok/asmodai 					++unreachable;
7070382be72SJeroen Ruigrok/asmodai 					printf(" !T");
7080382be72SJeroen Ruigrok/asmodai 					break;
7090382be72SJeroen Ruigrok/asmodai 				default:
7100382be72SJeroen Ruigrok/asmodai 					++unreachable;
7110382be72SJeroen Ruigrok/asmodai 					printf(" !<%d>", i - 1);
7120382be72SJeroen Ruigrok/asmodai 					break;
7130382be72SJeroen Ruigrok/asmodai 				}
7140382be72SJeroen Ruigrok/asmodai 				break;
7150382be72SJeroen Ruigrok/asmodai 			}
7160382be72SJeroen Ruigrok/asmodai 			if (cc == 0) {
7170382be72SJeroen Ruigrok/asmodai 				printf(" *");
7180382be72SJeroen Ruigrok/asmodai 				timeout++;
7190382be72SJeroen Ruigrok/asmodai 				loss++;
7200382be72SJeroen Ruigrok/asmodai 			}
72146877004SHasso Tepper 			else if (cc && probe == nprobes - 1 && Mflag)
72246877004SHasso Tepper 				decode_extensions(packet, cc);
72371126e33SSascha Wildner 			fflush(stdout);
7240382be72SJeroen Ruigrok/asmodai 		}
7250382be72SJeroen Ruigrok/asmodai 		if (sump)
7260382be72SJeroen Ruigrok/asmodai 			printf(" (%d%% loss)", (loss * 100) / nprobes);
7270382be72SJeroen Ruigrok/asmodai 		putchar('\n');
7280382be72SJeroen Ruigrok/asmodai 		if (got_there || (unreachable && (unreachable + timeout) >= nprobes))
7290382be72SJeroen Ruigrok/asmodai 			break;
7300382be72SJeroen Ruigrok/asmodai 	}
7310382be72SJeroen Ruigrok/asmodai 	exit(0);
7320382be72SJeroen Ruigrok/asmodai }
7330382be72SJeroen Ruigrok/asmodai 
734d6410035SSascha Wildner static int
wait_for_reply(int sock,struct sockaddr_in * from,struct timeval * sent)7350382be72SJeroen Ruigrok/asmodai wait_for_reply(int sock, struct sockaddr_in *from, struct timeval *sent)
7360382be72SJeroen Ruigrok/asmodai {
7370382be72SJeroen Ruigrok/asmodai 	socklen_t fromlen = sizeof (*from);
7380382be72SJeroen Ruigrok/asmodai 	struct timeval now, wait;
7390382be72SJeroen Ruigrok/asmodai 	int cc = 0, fdsn;
7400382be72SJeroen Ruigrok/asmodai 	fd_set *fdsp;
7410382be72SJeroen Ruigrok/asmodai 
7420382be72SJeroen Ruigrok/asmodai 	fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask);
7430382be72SJeroen Ruigrok/asmodai 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
7440382be72SJeroen Ruigrok/asmodai 		err(1, "malloc");
7450382be72SJeroen Ruigrok/asmodai 	memset(fdsp, 0, fdsn);
7460382be72SJeroen Ruigrok/asmodai 	FD_SET(sock, fdsp);
7470382be72SJeroen Ruigrok/asmodai 	gettimeofday(&now, NULL);
7480382be72SJeroen Ruigrok/asmodai 	wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec;
7490382be72SJeroen Ruigrok/asmodai 	wait.tv_usec =  sent->tv_usec - now.tv_usec;
7500382be72SJeroen Ruigrok/asmodai 	if (wait.tv_usec < 0) {
7510382be72SJeroen Ruigrok/asmodai 		wait.tv_usec += 1000000;
7520382be72SJeroen Ruigrok/asmodai 		wait.tv_sec--;
7530382be72SJeroen Ruigrok/asmodai 	}
7540382be72SJeroen Ruigrok/asmodai 	if (wait.tv_sec < 0)
7550382be72SJeroen Ruigrok/asmodai 		wait.tv_sec = wait.tv_usec = 0;
7560382be72SJeroen Ruigrok/asmodai 
75760233e58SSascha Wildner 	if (select(sock+1, fdsp, NULL, NULL, &wait) > 0)
7580382be72SJeroen Ruigrok/asmodai 		cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
7590382be72SJeroen Ruigrok/asmodai 		    (struct sockaddr *)from, &fromlen);
7600382be72SJeroen Ruigrok/asmodai 
7610382be72SJeroen Ruigrok/asmodai 	free(fdsp);
7620382be72SJeroen Ruigrok/asmodai 	return (cc);
7630382be72SJeroen Ruigrok/asmodai }
7640382be72SJeroen Ruigrok/asmodai 
765d6410035SSascha Wildner static void
decode_extensions(unsigned char * buf,int ip_len)76646877004SHasso Tepper decode_extensions(unsigned char *buf, int ip_len)
76746877004SHasso Tepper {
76846877004SHasso Tepper 	 uint32_t *cmn_hdr;
76946877004SHasso Tepper 	 struct icmp_ext_obj_hdr *obj_hdr;
77046877004SHasso Tepper 	 uint32_t mpls_hdr;
77146877004SHasso Tepper 	 int data_len, obj_len;
77246877004SHasso Tepper 	 struct ip *ip;
77346877004SHasso Tepper 
77446877004SHasso Tepper 	 ip = (struct ip *)buf;
77546877004SHasso Tepper 
77646877004SHasso Tepper 	 if (ip_len <= (int)(sizeof(struct ip) + ICMP_EXT_OFFSET)) {
77746877004SHasso Tepper 		/*
77846877004SHasso Tepper 		 * No support for ICMP extensions on this host
77946877004SHasso Tepper 		 */
78046877004SHasso Tepper 		return;
78146877004SHasso Tepper 	 }
78246877004SHasso Tepper 
78346877004SHasso Tepper 	 /*
78446877004SHasso Tepper 	  * Move forward to the start of the ICMP extensions, if present
78546877004SHasso Tepper 	  */
78646877004SHasso Tepper 	 buf += (ip->ip_hl << 2) + ICMP_EXT_OFFSET;
78746877004SHasso Tepper 	 cmn_hdr = (uint32_t *)buf;
78846877004SHasso Tepper 
78946877004SHasso Tepper 	 if (EXT_VERSION(ntohl(*cmn_hdr)) != ICMP_EXT_VERSION) {
79046877004SHasso Tepper 		/*
79146877004SHasso Tepper 		 * Unknown version
79246877004SHasso Tepper 		 */
79346877004SHasso Tepper 		return;
79446877004SHasso Tepper 	 }
79546877004SHasso Tepper 
79646877004SHasso Tepper 	 data_len = ip_len - ((u_char *)cmn_hdr - (u_char *)ip);
79746877004SHasso Tepper 
79846877004SHasso Tepper 	 /*
79946877004SHasso Tepper 	  * Check the checksum, cmn_hdr->checksum == 0 means no checksum'ing
80046877004SHasso Tepper 	  * done by sender.
80146877004SHasso Tepper 	  *
80246877004SHasso Tepper 	  * If the checksum is ok, we'll get 0, as the checksum is calculated
80346877004SHasso Tepper 	  * with the checksum field being 0'd.
80446877004SHasso Tepper 	  */
80546877004SHasso Tepper 	 if (EXT_CHECKSUM(ntohl(*cmn_hdr)) &&
80646877004SHasso Tepper 	     in_cksum((u_short *)cmn_hdr, data_len)) {
80746877004SHasso Tepper 		return;
80846877004SHasso Tepper 	 }
80946877004SHasso Tepper 
81046877004SHasso Tepper 	 buf += sizeof(*cmn_hdr);
81146877004SHasso Tepper 	 data_len -= sizeof(*cmn_hdr);
81246877004SHasso Tepper 
81346877004SHasso Tepper 	 while (data_len >= (int)sizeof(struct icmp_ext_obj_hdr)) {
81446877004SHasso Tepper 		unsigned char *nextbuf;
81546877004SHasso Tepper 
81646877004SHasso Tepper 		obj_hdr = (struct icmp_ext_obj_hdr *)buf;
81746877004SHasso Tepper 		obj_len = ntohs(obj_hdr->length);
81846877004SHasso Tepper 
81946877004SHasso Tepper 		/*
82046877004SHasso Tepper 		 * Sanity check the length field
82146877004SHasso Tepper 		 */
82246877004SHasso Tepper 		if (obj_len < (int)sizeof(*obj_hdr) || obj_len > data_len)
82346877004SHasso Tepper 			return;
82446877004SHasso Tepper 
82546877004SHasso Tepper 		/* Object has to be 4-byte aligned. */
82646877004SHasso Tepper 		if (obj_len & 3)
82746877004SHasso Tepper 			return;
82846877004SHasso Tepper 
82946877004SHasso Tepper 		nextbuf = buf + obj_len;
83046877004SHasso Tepper 		data_len -= obj_len;
83146877004SHasso Tepper 
83246877004SHasso Tepper 		/*
83346877004SHasso Tepper 		 * Move past the object header
83446877004SHasso Tepper 		 */
83546877004SHasso Tepper 		buf += sizeof(struct icmp_ext_obj_hdr);
83646877004SHasso Tepper 		obj_len -= sizeof(struct icmp_ext_obj_hdr);
83746877004SHasso Tepper 
83846877004SHasso Tepper 		switch (obj_hdr->class_num) {
83946877004SHasso Tepper 		case MPLS_STACK_ENTRY_CLASS:
84046877004SHasso Tepper 			switch (obj_hdr->c_type) {
84146877004SHasso Tepper 			case MPLS_STACK_ENTRY_C_TYPE:
84246877004SHasso Tepper 				while (obj_len >= (int)sizeof(uint32_t)) {
84346877004SHasso Tepper 					mpls_hdr = ntohl(*(uint32_t *)buf);
84446877004SHasso Tepper 
84546877004SHasso Tepper 					buf += sizeof(uint32_t);
84646877004SHasso Tepper 					obj_len -= sizeof(uint32_t);
84746877004SHasso Tepper 					printf(" [MPLS: Label %d Exp %d]",
84846877004SHasso Tepper 					    MPLS_LABEL(mpls_hdr),
84946877004SHasso Tepper 					    MPLS_EXP(mpls_hdr));
85046877004SHasso Tepper 				}
85146877004SHasso Tepper 				if (obj_len > 0) {
85246877004SHasso Tepper 					/*
85346877004SHasso Tepper 					 * Something went wrong, and we're at
85446877004SHasso Tepper 					 * a unknown offset into the packet,
85546877004SHasso Tepper 					 * ditch the rest of it.
85646877004SHasso Tepper 					 */
85746877004SHasso Tepper 					return;
85846877004SHasso Tepper 				}
85946877004SHasso Tepper 				break;
86046877004SHasso Tepper 			default:
86146877004SHasso Tepper 				/*
86246877004SHasso Tepper 				 * Unknown object, skip past it
86346877004SHasso Tepper 				 */
86446877004SHasso Tepper 				buf = nextbuf;
86546877004SHasso Tepper 				break;
86646877004SHasso Tepper 			}
86746877004SHasso Tepper 			break;
86846877004SHasso Tepper 
86946877004SHasso Tepper 		default:
87046877004SHasso Tepper 			/*
87146877004SHasso Tepper 			 * Unknown object, skip past it
87246877004SHasso Tepper 			 */
87346877004SHasso Tepper 			buf = nextbuf;
87446877004SHasso Tepper 			break;
87546877004SHasso Tepper 		}
87646877004SHasso Tepper 	}
87746877004SHasso Tepper }
87846877004SHasso Tepper 
879d6410035SSascha Wildner static void
dump_packet(void)8800382be72SJeroen Ruigrok/asmodai dump_packet(void)
8810382be72SJeroen Ruigrok/asmodai {
8820382be72SJeroen Ruigrok/asmodai 	u_char *p;
8830382be72SJeroen Ruigrok/asmodai 	int i;
8840382be72SJeroen Ruigrok/asmodai 
8850382be72SJeroen Ruigrok/asmodai 	fprintf(stderr, "packet data:");
8860382be72SJeroen Ruigrok/asmodai 	for (p = outpacket, i = 0; i < datalen; i++) {
8870382be72SJeroen Ruigrok/asmodai 		if ((i % 24) == 0)
8880382be72SJeroen Ruigrok/asmodai 			fprintf(stderr, "\n ");
8890382be72SJeroen Ruigrok/asmodai 		fprintf(stderr, " %02x", *p++);
8900382be72SJeroen Ruigrok/asmodai 	}
8910382be72SJeroen Ruigrok/asmodai 	fprintf(stderr, "\n");
8920382be72SJeroen Ruigrok/asmodai }
8930382be72SJeroen Ruigrok/asmodai 
894d6410035SSascha Wildner static void
send_probe(int seq,u_int8_t ttl,int iflag,struct sockaddr_in * to)8950382be72SJeroen Ruigrok/asmodai send_probe(int seq, u_int8_t ttl, int iflag, struct sockaddr_in *to)
8960382be72SJeroen Ruigrok/asmodai {
8970382be72SJeroen Ruigrok/asmodai 	struct ip *ip = (struct ip *)outpacket;
8980382be72SJeroen Ruigrok/asmodai 	u_char *p = (u_char *)(ip + 1);
8990382be72SJeroen Ruigrok/asmodai 	struct udphdr *up = (struct udphdr *)(p + lsrrlen);
9000382be72SJeroen Ruigrok/asmodai 	struct icmp *icmpp = (struct icmp *)(p + lsrrlen);
9010382be72SJeroen Ruigrok/asmodai 	struct packetdata *op;
9020382be72SJeroen Ruigrok/asmodai 	struct timeval tv;
9030382be72SJeroen Ruigrok/asmodai 	int i;
9040382be72SJeroen Ruigrok/asmodai 
90592b9bde7SEirik Nygaard 	ip->ip_len = datalen;
9060382be72SJeroen Ruigrok/asmodai 	ip->ip_ttl = ttl;
9070382be72SJeroen Ruigrok/asmodai 	ip->ip_id = htons(ident+seq);
9080382be72SJeroen Ruigrok/asmodai 
9090382be72SJeroen Ruigrok/asmodai 	switch (proto) {
9100382be72SJeroen Ruigrok/asmodai 	case IPPROTO_ICMP:
9110382be72SJeroen Ruigrok/asmodai 		icmpp->icmp_type = icmp_type;
9120382be72SJeroen Ruigrok/asmodai 		icmpp->icmp_code = icmp_code;
9130382be72SJeroen Ruigrok/asmodai 		icmpp->icmp_seq = htons(seq);
9140382be72SJeroen Ruigrok/asmodai 		icmpp->icmp_id = htons(ident);
9150382be72SJeroen Ruigrok/asmodai 		op = (struct packetdata *)(icmpp + 1);
9160382be72SJeroen Ruigrok/asmodai 		break;
9170382be72SJeroen Ruigrok/asmodai 	case IPPROTO_UDP:
9180382be72SJeroen Ruigrok/asmodai 		up->uh_sport = htons(ident);
9190382be72SJeroen Ruigrok/asmodai 		if (iflag)
9200382be72SJeroen Ruigrok/asmodai 			up->uh_dport = htons(port+seq);
9210382be72SJeroen Ruigrok/asmodai 		else
9220382be72SJeroen Ruigrok/asmodai 			up->uh_dport = htons(port);
9230382be72SJeroen Ruigrok/asmodai 		up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) -
9240382be72SJeroen Ruigrok/asmodai 		    lsrrlen));
9250382be72SJeroen Ruigrok/asmodai 		up->uh_sum = 0;
9260382be72SJeroen Ruigrok/asmodai 		op = (struct packetdata *)(up + 1);
9270382be72SJeroen Ruigrok/asmodai 		break;
9280382be72SJeroen Ruigrok/asmodai 	default:
9290382be72SJeroen Ruigrok/asmodai 		op = (struct packetdata *)(ip + 1);
9300382be72SJeroen Ruigrok/asmodai 		break;
9310382be72SJeroen Ruigrok/asmodai 	}
9320382be72SJeroen Ruigrok/asmodai 	op->seq = seq;
9330382be72SJeroen Ruigrok/asmodai 	op->ttl = ttl;
9340382be72SJeroen Ruigrok/asmodai 
9350382be72SJeroen Ruigrok/asmodai 	/*
9360382be72SJeroen Ruigrok/asmodai 	 * We don't want hostiles snooping the net to get any useful
9370382be72SJeroen Ruigrok/asmodai 	 * information about us. Send the timestamp in network byte order,
9380382be72SJeroen Ruigrok/asmodai 	 * and perturb the timestamp enough that they won't know our
9390382be72SJeroen Ruigrok/asmodai 	 * real clock ticker. We don't want to perturb the time by too
9400382be72SJeroen Ruigrok/asmodai 	 * much: being off by a suspiciously large amount might indicate
9410382be72SJeroen Ruigrok/asmodai 	 * OpenBSD.
9420382be72SJeroen Ruigrok/asmodai 	 *
9430382be72SJeroen Ruigrok/asmodai 	 * The timestamps in the packet are currently unused. If future
9440382be72SJeroen Ruigrok/asmodai 	 * work wants to use them they will have to subtract out the
9450382be72SJeroen Ruigrok/asmodai 	 * perturbation first.
9460382be72SJeroen Ruigrok/asmodai 	 */
94771126e33SSascha Wildner 	gettimeofday(&tv, NULL);
9480382be72SJeroen Ruigrok/asmodai 	op->sec = htonl(tv.tv_sec + sec_perturb);
9490382be72SJeroen Ruigrok/asmodai 	op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000);
9500382be72SJeroen Ruigrok/asmodai 
9510382be72SJeroen Ruigrok/asmodai 	if (proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) {
9520382be72SJeroen Ruigrok/asmodai 		icmpp->icmp_cksum = 0;
9530382be72SJeroen Ruigrok/asmodai 		icmpp->icmp_cksum = in_cksum((u_short *)icmpp,
9540382be72SJeroen Ruigrok/asmodai 		    datalen - sizeof(struct ip) - lsrrlen);
9550382be72SJeroen Ruigrok/asmodai 		if (icmpp->icmp_cksum == 0)
9560382be72SJeroen Ruigrok/asmodai 			icmpp->icmp_cksum = 0xffff;
9570382be72SJeroen Ruigrok/asmodai 	}
9580382be72SJeroen Ruigrok/asmodai 
9590382be72SJeroen Ruigrok/asmodai 	if (dump)
9600382be72SJeroen Ruigrok/asmodai 		dump_packet();
9610382be72SJeroen Ruigrok/asmodai 
9620382be72SJeroen Ruigrok/asmodai 	i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
9630382be72SJeroen Ruigrok/asmodai 	    sizeof(struct sockaddr_in));
9640382be72SJeroen Ruigrok/asmodai 	if (i < 0 || i != datalen)  {
9650382be72SJeroen Ruigrok/asmodai 		if (i < 0)
9660382be72SJeroen Ruigrok/asmodai 			perror("sendto");
9670382be72SJeroen Ruigrok/asmodai 		printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
9680382be72SJeroen Ruigrok/asmodai 		    datalen, i);
96971126e33SSascha Wildner 		fflush(stdout);
9700382be72SJeroen Ruigrok/asmodai 	}
9710382be72SJeroen Ruigrok/asmodai }
9720382be72SJeroen Ruigrok/asmodai 
9739dadf159SEirik Nygaard static const char *ttab[] = {
9740382be72SJeroen Ruigrok/asmodai 	"Echo Reply",
9750382be72SJeroen Ruigrok/asmodai 	"ICMP 1",
9760382be72SJeroen Ruigrok/asmodai 	"ICMP 2",
9770382be72SJeroen Ruigrok/asmodai 	"Dest Unreachable",
9780382be72SJeroen Ruigrok/asmodai 	"Source Quench",
9790382be72SJeroen Ruigrok/asmodai 	"Redirect",
9800382be72SJeroen Ruigrok/asmodai 	"ICMP 6",
9810382be72SJeroen Ruigrok/asmodai 	"ICMP 7",
9820382be72SJeroen Ruigrok/asmodai 	"Echo",
9830382be72SJeroen Ruigrok/asmodai 	"Router Advert",
9840382be72SJeroen Ruigrok/asmodai 	"Router Solicit",
9850382be72SJeroen Ruigrok/asmodai 	"Time Exceeded",
9860382be72SJeroen Ruigrok/asmodai 	"Param Problem",
9870382be72SJeroen Ruigrok/asmodai 	"Timestamp",
9880382be72SJeroen Ruigrok/asmodai 	"Timestamp Reply",
9890382be72SJeroen Ruigrok/asmodai 	"Info Request",
9900382be72SJeroen Ruigrok/asmodai 	"Info Reply",
9910382be72SJeroen Ruigrok/asmodai 	"Mask Request",
9920382be72SJeroen Ruigrok/asmodai 	"Mask Reply"
9930382be72SJeroen Ruigrok/asmodai };
9940382be72SJeroen Ruigrok/asmodai 
9950382be72SJeroen Ruigrok/asmodai /*
9960382be72SJeroen Ruigrok/asmodai  * Convert an ICMP "type" field to a printable string.
9970382be72SJeroen Ruigrok/asmodai  */
998d6410035SSascha Wildner static const char *
pr_type(u_int8_t t)9990382be72SJeroen Ruigrok/asmodai pr_type(u_int8_t t)
10000382be72SJeroen Ruigrok/asmodai {
10010382be72SJeroen Ruigrok/asmodai 	if (t > 18)
10020382be72SJeroen Ruigrok/asmodai 		return ("OUT-OF-RANGE");
10030382be72SJeroen Ruigrok/asmodai 	return (ttab[t]);
10040382be72SJeroen Ruigrok/asmodai }
10050382be72SJeroen Ruigrok/asmodai 
1006d6410035SSascha Wildner static int
packet_ok(u_char * buf,int cc,struct sockaddr_in * from,int seq,int iflag)10070382be72SJeroen Ruigrok/asmodai packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq, int iflag)
10080382be72SJeroen Ruigrok/asmodai {
10090382be72SJeroen Ruigrok/asmodai 	struct icmp *icp;
10100382be72SJeroen Ruigrok/asmodai 	u_char code;
10110382be72SJeroen Ruigrok/asmodai 	u_int8_t type;
10120382be72SJeroen Ruigrok/asmodai 	int hlen;
10130382be72SJeroen Ruigrok/asmodai #ifndef ARCHAIC
10140382be72SJeroen Ruigrok/asmodai 	struct ip *ip;
10150382be72SJeroen Ruigrok/asmodai 
10160382be72SJeroen Ruigrok/asmodai 	ip = (struct ip *) buf;
10170382be72SJeroen Ruigrok/asmodai 	hlen = ip->ip_hl << 2;
10180382be72SJeroen Ruigrok/asmodai 	if (cc < hlen + ICMP_MINLEN) {
10190382be72SJeroen Ruigrok/asmodai 		if (verbose)
10200382be72SJeroen Ruigrok/asmodai 			printf("packet too short (%d bytes) from %s\n", cc,
10210382be72SJeroen Ruigrok/asmodai 			    inet_ntoa(from->sin_addr));
10220382be72SJeroen Ruigrok/asmodai 		return (0);
10230382be72SJeroen Ruigrok/asmodai 	}
10240382be72SJeroen Ruigrok/asmodai 	cc -= hlen;
10250382be72SJeroen Ruigrok/asmodai 	icp = (struct icmp *)(buf + hlen);
10260382be72SJeroen Ruigrok/asmodai #else
10270382be72SJeroen Ruigrok/asmodai 	icp = (struct icmp *)buf;
10280382be72SJeroen Ruigrok/asmodai #endif /* ARCHAIC */
10290382be72SJeroen Ruigrok/asmodai 	type = icp->icmp_type;
10300382be72SJeroen Ruigrok/asmodai 	code = icp->icmp_code;
10310382be72SJeroen Ruigrok/asmodai 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
10320382be72SJeroen Ruigrok/asmodai 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
10330382be72SJeroen Ruigrok/asmodai 		struct ip *hip;
10340382be72SJeroen Ruigrok/asmodai 		struct udphdr *up;
10350382be72SJeroen Ruigrok/asmodai 		struct icmp *icmpp;
10360382be72SJeroen Ruigrok/asmodai 
10370382be72SJeroen Ruigrok/asmodai 		hip = &icp->icmp_ip;
10380382be72SJeroen Ruigrok/asmodai 		hlen = hip->ip_hl << 2;
10390382be72SJeroen Ruigrok/asmodai 
10400382be72SJeroen Ruigrok/asmodai 		switch (proto) {
10410382be72SJeroen Ruigrok/asmodai 		case IPPROTO_ICMP:
10420382be72SJeroen Ruigrok/asmodai 			if (icmp_type == ICMP_ECHO &&
10430382be72SJeroen Ruigrok/asmodai 			    type == ICMP_ECHOREPLY &&
10440382be72SJeroen Ruigrok/asmodai 			    icp->icmp_id == htons(ident) &&
10450382be72SJeroen Ruigrok/asmodai 			    icp->icmp_seq == htons(seq))
10460382be72SJeroen Ruigrok/asmodai 				return (-2); /* we got there */
10470382be72SJeroen Ruigrok/asmodai 
10480382be72SJeroen Ruigrok/asmodai 			icmpp = (struct icmp *)((u_char *)hip + hlen);
10490382be72SJeroen Ruigrok/asmodai 			if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP &&
10500382be72SJeroen Ruigrok/asmodai 			    icmpp->icmp_id == htons(ident) &&
10510382be72SJeroen Ruigrok/asmodai 			    icmpp->icmp_seq == htons(seq))
10520382be72SJeroen Ruigrok/asmodai 				return (type == ICMP_TIMXCEED? -1 : code + 1);
10530382be72SJeroen Ruigrok/asmodai 			break;
10540382be72SJeroen Ruigrok/asmodai 
10550382be72SJeroen Ruigrok/asmodai 		case IPPROTO_UDP:
10560382be72SJeroen Ruigrok/asmodai 			up = (struct udphdr *)((u_char *)hip + hlen);
10570382be72SJeroen Ruigrok/asmodai 			if (hlen + 12 <= cc && hip->ip_p == proto &&
10580382be72SJeroen Ruigrok/asmodai 			    up->uh_sport == htons(ident) &&
10590382be72SJeroen Ruigrok/asmodai 			    ((iflag && up->uh_dport == htons(port + seq)) ||
10600382be72SJeroen Ruigrok/asmodai 			    (!iflag && up->uh_dport == htons(port))))
10610382be72SJeroen Ruigrok/asmodai 				return (type == ICMP_TIMXCEED? -1 : code + 1);
10620382be72SJeroen Ruigrok/asmodai 			break;
10630382be72SJeroen Ruigrok/asmodai 		default:
10640382be72SJeroen Ruigrok/asmodai 			/* this is some odd, user specified proto,
10650382be72SJeroen Ruigrok/asmodai 			 * how do we check it?
10660382be72SJeroen Ruigrok/asmodai 			 */
10670382be72SJeroen Ruigrok/asmodai 			if (hip->ip_p == proto)
10680382be72SJeroen Ruigrok/asmodai 				return (type == ICMP_TIMXCEED? -1 : code + 1);
10690382be72SJeroen Ruigrok/asmodai 		}
10700382be72SJeroen Ruigrok/asmodai 	}
10710382be72SJeroen Ruigrok/asmodai #ifndef ARCHAIC
10720382be72SJeroen Ruigrok/asmodai 	if (verbose) {
10730382be72SJeroen Ruigrok/asmodai 		int i;
10740382be72SJeroen Ruigrok/asmodai 		in_addr_t *lp = (in_addr_t *)&icp->icmp_ip;
10750382be72SJeroen Ruigrok/asmodai 
10760382be72SJeroen Ruigrok/asmodai 		printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr));
10770382be72SJeroen Ruigrok/asmodai 		printf(" to %s", inet_ntoa(ip->ip_dst));
10780382be72SJeroen Ruigrok/asmodai 		printf(": icmp type %u (%s) code %d\n", type, pr_type(type),
10790382be72SJeroen Ruigrok/asmodai 		    icp->icmp_code);
10800382be72SJeroen Ruigrok/asmodai 		for (i = 4; i < cc ; i += sizeof(in_addr_t))
10810382be72SJeroen Ruigrok/asmodai 			printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++);
10820382be72SJeroen Ruigrok/asmodai 	}
10830382be72SJeroen Ruigrok/asmodai #endif /* ARCHAIC */
10840382be72SJeroen Ruigrok/asmodai 	return (0);
10850382be72SJeroen Ruigrok/asmodai }
10860382be72SJeroen Ruigrok/asmodai 
1087d6410035SSascha Wildner static void
print(u_char * buf,int cc,struct sockaddr_in * from)10880382be72SJeroen Ruigrok/asmodai print(u_char *buf, int cc, struct sockaddr_in *from)
10890382be72SJeroen Ruigrok/asmodai {
10900382be72SJeroen Ruigrok/asmodai 	struct ip *ip;
10910382be72SJeroen Ruigrok/asmodai 	int hlen;
10920382be72SJeroen Ruigrok/asmodai 
10930382be72SJeroen Ruigrok/asmodai 	ip = (struct ip *) buf;
10940382be72SJeroen Ruigrok/asmodai 	hlen = ip->ip_hl << 2;
10950382be72SJeroen Ruigrok/asmodai 	cc -= hlen;
10960382be72SJeroen Ruigrok/asmodai 
10970382be72SJeroen Ruigrok/asmodai 	if (nflag)
10980382be72SJeroen Ruigrok/asmodai 		printf(" %s", inet_ntoa(from->sin_addr));
10990382be72SJeroen Ruigrok/asmodai 	else
11000382be72SJeroen Ruigrok/asmodai 		printf(" %s (%s)", inetname(from->sin_addr),
11010382be72SJeroen Ruigrok/asmodai 		    inet_ntoa(from->sin_addr));
11020382be72SJeroen Ruigrok/asmodai 
11030382be72SJeroen Ruigrok/asmodai 	if (verbose)
11040382be72SJeroen Ruigrok/asmodai 		printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
11050382be72SJeroen Ruigrok/asmodai }
11060382be72SJeroen Ruigrok/asmodai 
11070382be72SJeroen Ruigrok/asmodai 
11080382be72SJeroen Ruigrok/asmodai /*
11090382be72SJeroen Ruigrok/asmodai  * Checksum routine for Internet Protocol family headers (C Version)
11100382be72SJeroen Ruigrok/asmodai  */
1111d6410035SSascha Wildner static u_short
in_cksum(u_short * addr,int len)11120382be72SJeroen Ruigrok/asmodai in_cksum(u_short *addr, int len)
11130382be72SJeroen Ruigrok/asmodai {
11140382be72SJeroen Ruigrok/asmodai 	u_short *w = addr, answer;
11150382be72SJeroen Ruigrok/asmodai 	int nleft = len, sum = 0;
11160382be72SJeroen Ruigrok/asmodai 
11170382be72SJeroen Ruigrok/asmodai 	/*
11180382be72SJeroen Ruigrok/asmodai 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
11190382be72SJeroen Ruigrok/asmodai 	 *  we add sequential 16 bit words to it, and at the end, fold
11200382be72SJeroen Ruigrok/asmodai 	 *  back all the carry bits from the top 16 bits into the lower
11210382be72SJeroen Ruigrok/asmodai 	 *  16 bits.
11220382be72SJeroen Ruigrok/asmodai 	 */
11230382be72SJeroen Ruigrok/asmodai 	while (nleft > 1)  {
11240382be72SJeroen Ruigrok/asmodai 		sum += *w++;
11250382be72SJeroen Ruigrok/asmodai 		nleft -= 2;
11260382be72SJeroen Ruigrok/asmodai 	}
11270382be72SJeroen Ruigrok/asmodai 
11280382be72SJeroen Ruigrok/asmodai 	/* mop up an odd byte, if necessary */
11290382be72SJeroen Ruigrok/asmodai 	if (nleft == 1)
11300382be72SJeroen Ruigrok/asmodai 		sum += *(u_char *)w;
11310382be72SJeroen Ruigrok/asmodai 
11320382be72SJeroen Ruigrok/asmodai 	/*
11330382be72SJeroen Ruigrok/asmodai 	 * add back carry outs from top 16 bits to low 16 bits
11340382be72SJeroen Ruigrok/asmodai 	 */
11350382be72SJeroen Ruigrok/asmodai 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
11360382be72SJeroen Ruigrok/asmodai 	sum += (sum >> 16);			/* add carry */
11370382be72SJeroen Ruigrok/asmodai 	answer = ~sum;				/* truncate to 16 bits */
11380382be72SJeroen Ruigrok/asmodai 	return (answer);
11390382be72SJeroen Ruigrok/asmodai }
11400382be72SJeroen Ruigrok/asmodai 
11410382be72SJeroen Ruigrok/asmodai /*
11420382be72SJeroen Ruigrok/asmodai  * Construct an Internet address representation.
11430382be72SJeroen Ruigrok/asmodai  * If the nflag has been supplied, give
11440382be72SJeroen Ruigrok/asmodai  * numeric value, otherwise try for symbolic name.
11450382be72SJeroen Ruigrok/asmodai  */
1146d6410035SSascha Wildner static char *
inetname(struct in_addr in)11470382be72SJeroen Ruigrok/asmodai inetname(struct in_addr in)
11480382be72SJeroen Ruigrok/asmodai {
11490382be72SJeroen Ruigrok/asmodai 	static char domain[MAXHOSTNAMELEN], line[MAXHOSTNAMELEN];
11500382be72SJeroen Ruigrok/asmodai 	static int first = 1;
11510382be72SJeroen Ruigrok/asmodai 	struct hostent *hp;
11520382be72SJeroen Ruigrok/asmodai 	char *cp;
11530382be72SJeroen Ruigrok/asmodai 
11540382be72SJeroen Ruigrok/asmodai 	if (first && !nflag) {
11550382be72SJeroen Ruigrok/asmodai 		first = 0;
11560382be72SJeroen Ruigrok/asmodai 		if (gethostname(domain, sizeof domain) == 0 &&
11570382be72SJeroen Ruigrok/asmodai 		    (cp = strchr(domain, '.')) != NULL) {
11580382be72SJeroen Ruigrok/asmodai 			strlcpy(domain, cp + 1, sizeof(domain));
11590382be72SJeroen Ruigrok/asmodai 		}
11600382be72SJeroen Ruigrok/asmodai 	}
11610382be72SJeroen Ruigrok/asmodai 	if (!nflag && in.s_addr != INADDR_ANY) {
116215b85273SSascha Wildner 		hp = gethostbyaddr(&in, sizeof(in), AF_INET);
11630382be72SJeroen Ruigrok/asmodai 		if (hp != NULL) {
11640382be72SJeroen Ruigrok/asmodai 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
11650382be72SJeroen Ruigrok/asmodai 			    strcmp(cp + 1, domain) == 0)
11660382be72SJeroen Ruigrok/asmodai 				*cp = '\0';
11670382be72SJeroen Ruigrok/asmodai 			strlcpy(line, hp->h_name, sizeof(line));
11680382be72SJeroen Ruigrok/asmodai 			return (line);
11690382be72SJeroen Ruigrok/asmodai 		}
11700382be72SJeroen Ruigrok/asmodai 	}
11710382be72SJeroen Ruigrok/asmodai 	return (inet_ntoa(in));
11720382be72SJeroen Ruigrok/asmodai }
11730382be72SJeroen Ruigrok/asmodai 
1174d6410035SSascha Wildner static void
usage(void)11750382be72SJeroen Ruigrok/asmodai usage(void)
11760382be72SJeroen Ruigrok/asmodai {
11770382be72SJeroen Ruigrok/asmodai 	fprintf(stderr,
117846877004SHasso Tepper 	    "usage: %s [-cdDIlMnrSv] [-f first_ttl] [-g gateway_addr] [-m max_ttl]\n"
11790382be72SJeroen Ruigrok/asmodai 	    "\t[-p port] [-P proto] [-q nqueries] [-s src_addr] [-t tos]\n"
11809dadf159SEirik Nygaard 	    "\t[-w waittime] host [packetsize]\n", getprogname());
11810382be72SJeroen Ruigrok/asmodai 	exit(1);
11820382be72SJeroen Ruigrok/asmodai }
1183