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