traceroute.c revision 77816
118579Sfenner/*
218579Sfenner * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996
318579Sfenner *	The Regents of the University of California.  All rights reserved.
418579Sfenner *
518579Sfenner * Redistribution and use in source and binary forms, with or without
618579Sfenner * modification, are permitted provided that: (1) source code distributions
718579Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
818579Sfenner * distributions including binary code include the above copyright notice and
918579Sfenner * this paragraph in its entirety in the documentation or other materials
1018579Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1118579Sfenner * features or use of this software display the following acknowledgement:
1218579Sfenner * ``This product includes software developed by the University of California,
1318579Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1418579Sfenner * the University nor the names of its contributors may be used to endorse
1518579Sfenner * or promote products derived from this software without specific prior
1618579Sfenner * written permission.
1718579Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1818579Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1918579Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2018579Sfenner */
2118579Sfenner
2218579Sfenner#ifndef lint
2318579Sfennerstatic const char copyright[] =
2418579Sfenner    "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996\n\
2518579SfennerThe Regents of the University of California.  All rights reserved.\n";
2658835Sshin#if 0
2718579Sfennerstatic const char rcsid[] =
2858835Sshin    "@(#)$Header: traceroute.c,v 1.43 96/09/27 20:08:10 leres Exp $ (LBL)";
2918579Sfenner#endif
3058835Sshinstatic const char rcsid[] =
3158835Sshin    "$FreeBSD: head/contrib/traceroute/traceroute.c 77816 2001-06-06 16:12:59Z ru $";
3258835Sshin#endif
3318579Sfenner
3418579Sfenner/*
3518579Sfenner * traceroute host  - trace the route ip packets follow going to "host".
3618579Sfenner *
3718579Sfenner * Attempt to trace the route an ip packet would follow to some
3818579Sfenner * internet host.  We find out intermediate hops by launching probe
3918579Sfenner * packets with a small ttl (time to live) then listening for an
4018579Sfenner * icmp "time exceeded" reply from a gateway.  We start our probes
4118579Sfenner * with a ttl of one and increase by one until we get an icmp "port
4218579Sfenner * unreachable" (which means we got to "host") or hit a max (which
4377816Sru * defaults to net.inet.ip.ttl hops & can be changed with the -m flag).
4477816Sru * Three probes (change with -q flag) are sent at each ttl setting and
4577816Sru * a line is printed showing the ttl, address of the gateway and
4618579Sfenner * round trip time of each probe.  If the probe answers come from
4718579Sfenner * different gateways, the address of each responding system will
4818579Sfenner * be printed.  If there is no response within a 5 sec. timeout
4918579Sfenner * interval (changed with the -w flag), a "*" is printed for that
5018579Sfenner * probe.
5118579Sfenner *
5218579Sfenner * Probe packets are UDP format.  We don't want the destination
5318579Sfenner * host to process them so the destination port is set to an
5418579Sfenner * unlikely value (if some clod on the destination is using that
5518579Sfenner * value, it can be changed with the -p flag).
5618579Sfenner *
5718579Sfenner * A sample use might be:
5818579Sfenner *
5918579Sfenner *     [yak 71]% traceroute nis.nsf.net.
6077816Sru *     traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
6118579Sfenner *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
6218579Sfenner *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
6318579Sfenner *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
6418579Sfenner *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
6518579Sfenner *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
6618579Sfenner *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
6718579Sfenner *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
6818579Sfenner *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
6918579Sfenner *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
7018579Sfenner *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
7118579Sfenner *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
7218579Sfenner *
7318579Sfenner * Note that lines 2 & 3 are the same.  This is due to a buggy
7418579Sfenner * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
7518579Sfenner * packets with a zero ttl.
7618579Sfenner *
7718579Sfenner * A more interesting example is:
7818579Sfenner *
7918579Sfenner *     [yak 72]% traceroute allspice.lcs.mit.edu.
8077816Sru *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
8118579Sfenner *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
8218579Sfenner *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
8318579Sfenner *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
8418579Sfenner *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
8518579Sfenner *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
8618579Sfenner *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
8718579Sfenner *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
8818579Sfenner *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
8918579Sfenner *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
9018579Sfenner *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
9118579Sfenner *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
9218579Sfenner *     12  * * *
9318579Sfenner *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
9418579Sfenner *     14  * * *
9518579Sfenner *     15  * * *
9618579Sfenner *     16  * * *
9718579Sfenner *     17  * * *
9818579Sfenner *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
9918579Sfenner *
10018579Sfenner * (I start to see why I'm having so much trouble with mail to
10118579Sfenner * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
10218579Sfenner * either don't send ICMP "time exceeded" messages or send them
10318579Sfenner * with a ttl too small to reach us.  14 - 17 are running the
10418579Sfenner * MIT C Gateway code that doesn't send "time exceeded"s.  God
10518579Sfenner * only knows what's going on with 12.
10618579Sfenner *
10718579Sfenner * The silent gateway 12 in the above may be the result of a bug in
10818579Sfenner * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
10918579Sfenner * sends an unreachable message using whatever ttl remains in the
11018579Sfenner * original datagram.  Since, for gateways, the remaining ttl is
11118579Sfenner * zero, the icmp "time exceeded" is guaranteed to not make it back
11218579Sfenner * to us.  The behavior of this bug is slightly more interesting
11318579Sfenner * when it appears on the destination system:
11418579Sfenner *
11518579Sfenner *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
11618579Sfenner *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
11718579Sfenner *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
11818579Sfenner *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
11918579Sfenner *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
12018579Sfenner *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
12118579Sfenner *      7  * * *
12218579Sfenner *      8  * * *
12318579Sfenner *      9  * * *
12418579Sfenner *     10  * * *
12518579Sfenner *     11  * * *
12618579Sfenner *     12  * * *
12718579Sfenner *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
12818579Sfenner *
12918579Sfenner * Notice that there are 12 "gateways" (13 is the final
13018579Sfenner * destination) and exactly the last half of them are "missing".
13118579Sfenner * What's really happening is that rip (a Sun-3 running Sun OS3.5)
13218579Sfenner * is using the ttl from our arriving datagram as the ttl in its
13318579Sfenner * icmp reply.  So, the reply will time out on the return path
13418579Sfenner * (with no notice sent to anyone since icmp's aren't sent for
13518579Sfenner * icmp's) until we probe with a ttl that's at least twice the path
13618579Sfenner * length.  I.e., rip is really only 7 hops away.  A reply that
13718579Sfenner * returns with a ttl of 1 is a clue this problem exists.
13818579Sfenner * Traceroute prints a "!" after the time if the ttl is <= 1.
13918579Sfenner * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
14018579Sfenner * non-standard (HPUX) software, expect to see this problem
14118579Sfenner * frequently and/or take care picking the target host of your
14218579Sfenner * probes.
14318579Sfenner *
14418579Sfenner * Other possible annotations after the time are !H, !N, !P (got a host,
14518579Sfenner * network or protocol unreachable, respectively), !S or !F (source
14618579Sfenner * route failed or fragmentation needed -- neither of these should
14718579Sfenner * ever occur and the associated gateway is busted if you see one).  If
14818579Sfenner * almost all the probes result in some kind of unreachable, traceroute
14918579Sfenner * will give up and exit.
15018579Sfenner *
15118579Sfenner * Notes
15218579Sfenner * -----
15318579Sfenner * This program must be run by root or be setuid.  (I suggest that
15418579Sfenner * you *don't* make it setuid -- casual use could result in a lot
15518579Sfenner * of unnecessary traffic on our poor, congested nets.)
15618579Sfenner *
15718579Sfenner * This program requires a kernel mod that does not appear in any
15818579Sfenner * system available from Berkeley:  A raw ip socket using proto
15918579Sfenner * IPPROTO_RAW must interpret the data sent as an ip datagram (as
16018579Sfenner * opposed to data to be wrapped in a ip datagram).  See the README
16118579Sfenner * file that came with the source to this program for a description
16218579Sfenner * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
16318579Sfenner * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
16418579Sfenner * MODIFIED TO RUN THIS PROGRAM.
16518579Sfenner *
16618579Sfenner * The udp port usage may appear bizarre (well, ok, it is bizarre).
16718579Sfenner * The problem is that an icmp message only contains 8 bytes of
16818579Sfenner * data from the original datagram.  8 bytes is the size of a udp
16918579Sfenner * header so, if we want to associate replies with the original
17018579Sfenner * datagram, the necessary information must be encoded into the
17118579Sfenner * udp header (the ip id could be used but there's no way to
17218579Sfenner * interlock with the kernel's assignment of ip id's and, anyway,
17318579Sfenner * it would have taken a lot more kernel hacking to allow this
17418579Sfenner * code to set the ip id).  So, to allow two or more users to
17518579Sfenner * use traceroute simultaneously, we use this task's pid as the
17618579Sfenner * source port (the high bit is set to move the port number out
17718579Sfenner * of the "likely" range).  To keep track of which probe is being
17818579Sfenner * replied to (so times and/or hop counts don't get confused by a
17918579Sfenner * reply that was delayed in transit), we increment the destination
18018579Sfenner * port number before each probe.
18118579Sfenner *
18218579Sfenner * Don't use this as a coding example.  I was trying to find a
18318579Sfenner * routing problem and this code sort-of popped out after 48 hours
18418579Sfenner * without sleep.  I was amazed it ever compiled, much less ran.
18518579Sfenner *
18618579Sfenner * I stole the idea for this program from Steve Deering.  Since
18718579Sfenner * the first release, I've learned that had I attended the right
18818579Sfenner * IETF working group meetings, I also could have stolen it from Guy
18918579Sfenner * Almes or Matt Mathis.  I don't know (or care) who came up with
19018579Sfenner * the idea first.  I envy the originators' perspicacity and I'm
19118579Sfenner * glad they didn't keep the idea a secret.
19218579Sfenner *
19318579Sfenner * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
19418579Sfenner * enhancements to the original distribution.
19518579Sfenner *
19618579Sfenner * I've hacked up a round-trip-route version of this that works by
19718579Sfenner * sending a loose-source-routed udp datagram through the destination
19818579Sfenner * back to yourself.  Unfortunately, SO many gateways botch source
19918579Sfenner * routing, the thing is almost worthless.  Maybe one day...
20018579Sfenner *
20118579Sfenner *  -- Van Jacobson (van@ee.lbl.gov)
20218579Sfenner *     Tue Dec 20 03:50:13 PST 1988
20318579Sfenner */
20418579Sfenner
20518579Sfenner#include <sys/param.h>
20618579Sfenner#include <sys/file.h>
20718579Sfenner#include <sys/ioctl.h>
20818579Sfenner#ifdef HAVE_SYS_SELECT_H
20918579Sfenner#include <sys/select.h>
21018579Sfenner#endif
21118579Sfenner#include <sys/socket.h>
21277816Sru#ifdef HAVE_SYS_SYSCTL_H
21377816Sru#include <sys/sysctl.h>
21477816Sru#endif
21518579Sfenner#include <sys/time.h>
21618579Sfenner
21718579Sfenner#include <netinet/in_systm.h>
21818579Sfenner#include <netinet/in.h>
21918579Sfenner#include <netinet/ip.h>
22018579Sfenner#include <netinet/ip_var.h>
22118579Sfenner#include <netinet/ip_icmp.h>
22218579Sfenner#include <netinet/udp.h>
22346542Sarchie#include <netinet/tcp.h>
22418579Sfenner
22518579Sfenner#include <arpa/inet.h>
22618579Sfenner
22758804Sshin#ifdef	IPSEC
22858804Sshin#include <net/route.h>
22958804Sshin#include <netinet6/ipsec.h>	/* XXX */
23058804Sshin#endif	/* IPSEC */
23158804Sshin
23218579Sfenner#include <ctype.h>
23318579Sfenner#include <errno.h>
23418579Sfenner#ifdef HAVE_MALLOC_H
23518579Sfenner#include <malloc.h>
23618579Sfenner#endif
23718579Sfenner#include <memory.h>
23818579Sfenner#include <netdb.h>
23918579Sfenner#include <stdio.h>
24018579Sfenner#include <stdlib.h>
24118579Sfenner#include <string.h>
24218579Sfenner#include <unistd.h>
24318579Sfenner
24418579Sfenner#include "gnuc.h"
24518579Sfenner#ifdef HAVE_OS_PROTO_H
24618579Sfenner#include "os-proto.h"
24718579Sfenner#endif
24818579Sfenner
24918579Sfenner/* Maximum number of gateways (include room for one noop) */
25018579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
25118579Sfenner
25218579Sfenner#ifndef MAXHOSTNAMELEN
25318579Sfenner#define MAXHOSTNAMELEN	64
25418579Sfenner#endif
25518579Sfenner
25618579Sfenner#define Fprintf (void)fprintf
25718579Sfenner#define Printf (void)printf
25818579Sfenner
25946542Sarchie/* What a GRE packet header looks like */
26046542Sarchiestruct grehdr {
26146542Sarchie	u_int16_t   flags;
26246542Sarchie	u_int16_t   proto;
26346542Sarchie	u_int16_t   length;	/* PPTP version of these fields */
26446542Sarchie	u_int16_t   callId;
26546542Sarchie};
26646542Sarchie#ifndef IPPROTO_GRE
26746542Sarchie#define IPPROTO_GRE	47
26846542Sarchie#endif
26946542Sarchie
27046542Sarchie/* For GRE, we prepare what looks like a PPTP packet */
27146542Sarchie#define GRE_PPTP_PROTO	0x880b
27246542Sarchie
27318579Sfenner/* Data section of the probe packet */
27418579Sfennerstruct outdata {
27518579Sfenner	u_char seq;		/* sequence number of this packet */
27618579Sfenner	u_char ttl;		/* ttl packet left with */
27718579Sfenner	struct timeval tv;	/* time packet left */
27818579Sfenner};
27918579Sfenner
28046542Sarchie/* Descriptor structure for each outgoing protocol we support */
28146542Sarchiestruct outproto {
28246542Sarchie	char	*name;		/* name of protocol */
28346542Sarchie	u_char	num;		/* IP protocol number */
28446542Sarchie	u_short	hdrlen;		/* max size of protocol header */
28546542Sarchie	u_short	port;		/* default base protocol-specific "port" */
28646542Sarchie	void	(*prepare)(struct outdata *);
28746542Sarchie				/* finish preparing an outgoing packet */
28846542Sarchie	int	(*check)(const u_char *, int);
28946542Sarchie				/* check an incoming packet */
29046542Sarchie};
29146542Sarchie
29218579Sfenneru_char	packet[512];		/* last inbound (icmp) packet */
29318579Sfenner
29446542Sarchiestruct ip *outip;		/* last output ip packet */
29546542Sarchieu_char *outprot;		/* last output inner protocol packet */
29618579Sfenner
29718579Sfenner/* loose source route gateway list (including room for final destination) */
29818579Sfenneru_int32_t gwlist[NGATEWAYS + 1];
29918579Sfenner
30018579Sfennerint s;				/* receive (icmp) socket file descriptor */
30118579Sfennerint sndsock;			/* send (udp) socket file descriptor */
30218579Sfenner
30318579Sfennerstruct sockaddr whereto;	/* Who to try to reach */
30418579Sfennerint packlen;			/* total length of packet */
30546542Sarchieint protlen;			/* length of protocol part of packet */
30618579Sfennerint maxpacket = 32 * 1024;	/* max ip packet size */
30718579Sfenner
30818579Sfennerchar *prog;
30918579Sfennerchar *source;
31018579Sfennerchar *hostname;
31118579Sfenner
31218579Sfennerint nprobes = 3;
31347071Sarchieint min_ttl = 1;
31477816Sruint max_ttl;
31518579Sfenneru_short ident;
31646542Sarchieu_short port;			/* protocol specific base "port" */
31718579Sfenner
31818579Sfennerint options;			/* socket options */
31918579Sfennerint verbose;
32018579Sfennerint waittime = 5;		/* time to wait for response (in seconds) */
32118579Sfennerint nflag;			/* print addresses numerically */
32218579Sfenner
32318579Sfennerextern int optind;
32418579Sfennerextern int opterr;
32518579Sfennerextern char *optarg;
32618579Sfenner
32718579Sfenner/* Forwards */
32818579Sfennerdouble	deltaT(struct timeval *, struct timeval *);
32918579Sfennerchar	*inetname(struct in_addr);
33018579Sfennerint	main(int, char **);
33118579Sfennerint	packet_ok(u_char *, int, struct sockaddr_in *, int);
33218579Sfennerchar	*pr_type(u_char);
33318579Sfennervoid	print(u_char *, int, struct sockaddr_in *);
33418579Sfennerchar	*getaddr(u_int32_t *, char *);
33518579Sfennerchar	*getsin(struct sockaddr_in *, char *);
33618579Sfennerchar	*savestr(const char *);
33758804Sshin#ifdef	IPSEC
33858804Sshinint	setpolicy __P((int so, char *policy));
33958804Sshin#endif
34046542Sarchievoid	send_probe(int, int);
34118579Sfennervoid	tvsub(struct timeval *, struct timeval *);
34267682Sobrienvoid usage(void);
34318579Sfennerint	wait_for_reply(int, struct sockaddr_in *, struct timeval *);
34418579Sfenner
34546542Sarchievoid	udp_prep(struct outdata *);
34646542Sarchieint	udp_check(const u_char *, int);
34746542Sarchievoid	tcp_prep(struct outdata *);
34846542Sarchieint	tcp_check(const u_char *, int);
34946542Sarchievoid	gre_prep(struct outdata *);
35046542Sarchieint	gre_check(const u_char *, int);
35146542Sarchievoid	gen_prep(struct outdata *);
35246542Sarchieint	gen_check(const u_char *, int);
35346542Sarchie
35446542Sarchie/* List of supported protocols. The first one is the default. The last
35546542Sarchie   one is the handler for generic protocols not explicitly listed. */
35646542Sarchiestruct	outproto protos[] = {
35746542Sarchie	{
35846542Sarchie		"udp",
35946542Sarchie		IPPROTO_UDP,
36046542Sarchie		sizeof(struct udphdr),
36146542Sarchie		32768 + 666,
36246542Sarchie		udp_prep,
36346542Sarchie		udp_check
36446542Sarchie	},
36546542Sarchie	{
36646542Sarchie		"tcp",
36746542Sarchie		IPPROTO_TCP,
36846542Sarchie		sizeof(struct tcphdr),
36946542Sarchie		32768 + 666,
37046542Sarchie		tcp_prep,
37146542Sarchie		tcp_check
37246542Sarchie	},
37346542Sarchie	{
37446542Sarchie		"gre",
37546542Sarchie		IPPROTO_GRE,
37646542Sarchie		sizeof(struct grehdr),
37746542Sarchie		GRE_PPTP_PROTO,
37846542Sarchie		gre_prep,
37946542Sarchie		gre_check
38046542Sarchie	},
38146542Sarchie	{
38246542Sarchie		NULL,
38346542Sarchie		0,
38446542Sarchie		2 * sizeof(u_short),
38546542Sarchie		0,
38646542Sarchie		gen_prep,
38746542Sarchie		gen_check
38846542Sarchie	},
38946542Sarchie};
39046542Sarchiestruct	outproto *proto = &protos[0];
39146542Sarchie
39218579Sfennerint
39318579Sfennermain(int argc, char **argv)
39418579Sfenner{
39518579Sfenner	register int op, code;
39618579Sfenner	register char *cp;
39718579Sfenner	struct sockaddr_in from;
39818579Sfenner	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
39918579Sfenner	int on = 1;
40018579Sfenner	register struct protoent *pe;
40118579Sfenner	register int ttl, probe, i;
40218579Sfenner	register int seq = 0;
40318579Sfenner	register int tos = 0;
40418579Sfenner	register int lsrr = 0;
40518579Sfenner	register int optlen = 0;
40648221Sarchie	int requestPort = -1;
40718803Ssef	int sump = 0;
40818583Sfenner	int sockerrno;
40918579Sfenner
41018583Sfenner	/*
41118583Sfenner	 * Do the setuid-required stuff first, then lose priveleges ASAP.
41218583Sfenner	 * Do error checking for these two calls where they appeared in
41318583Sfenner	 * the original code.
41418583Sfenner	 */
41518583Sfenner	cp = "icmp";
41618583Sfenner	pe = getprotobyname(cp);
41718583Sfenner	if (pe) {
41818583Sfenner		if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
41918583Sfenner			sockerrno = errno;
42018583Sfenner		else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
42118583Sfenner			sockerrno = errno;
42218583Sfenner	}
42318583Sfenner
42418583Sfenner	setuid(getuid());
42518583Sfenner
42677816Sru#ifdef IPCTL_DEFTTL
42777816Sru	{
42877816Sru		int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
42977816Sru		size_t sz = sizeof(max_ttl);
43077816Sru
43177816Sru		if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1)
43277816Sru			err(1, "sysctl(net.inet.ip.ttl)");
43377816Sru	}
43477816Sru#else
43577816Sru	max_ttl = 30;
43677816Sru#endif
43777816Sru
43818579Sfenner	if ((cp = strrchr(argv[0], '/')) != NULL)
43918579Sfenner		prog = cp + 1;
44018579Sfenner	else
44118579Sfenner		prog = argv[0];
44218579Sfenner
44318579Sfenner	opterr = 0;
44447071Sarchie	while ((op = getopt(argc, argv, "Sdnrvg:M:m:P:p:q:s:t:w:")) != EOF)
44518579Sfenner		switch (op) {
44618579Sfenner
44718803Ssef		case 'S':
44818803Ssef			sump = 1;
44918803Ssef			break;
45018579Sfenner		case 'd':
45118579Sfenner			options |= SO_DEBUG;
45218579Sfenner			break;
45318579Sfenner
45418579Sfenner		case 'g':
45518579Sfenner			if (lsrr >= NGATEWAYS) {
45618579Sfenner				Fprintf(stderr,
45718579Sfenner				    "%s: No more than %d gateways\n",
45818579Sfenner				    prog, NGATEWAYS);
45918579Sfenner				exit(1);
46018579Sfenner			}
46118579Sfenner			(void)getaddr(gwlist + lsrr, optarg);
46218579Sfenner			++lsrr;
46318579Sfenner			break;
46418579Sfenner
46547071Sarchie		case 'M':
46647071Sarchie			min_ttl = atoi(optarg);
46747071Sarchie			if (min_ttl < 1 || min_ttl > 0xff) {
46847071Sarchie				Fprintf(stderr, "%s: invalid ttl value %s\n",
46947071Sarchie				    prog, optarg);
47047071Sarchie				exit(1);
47147071Sarchie			}
47247071Sarchie			break;
47347071Sarchie
47418579Sfenner		case 'm':
47518579Sfenner			max_ttl = atoi(optarg);
47647071Sarchie			if (max_ttl < 1 || max_ttl > 0xff) {
47747071Sarchie				Fprintf(stderr, "%s: invalid ttl value %s\n",
47847071Sarchie				    prog, optarg);
47918579Sfenner				exit(1);
48018579Sfenner			}
48118579Sfenner			break;
48218579Sfenner
48318579Sfenner		case 'n':
48418579Sfenner			++nflag;
48518579Sfenner			break;
48618579Sfenner
48746542Sarchie		case 'P':
48846542Sarchie			for (i = 0; protos[i].name != NULL; i++) {
48946542Sarchie				if (strcasecmp(protos[i].name, optarg) == 0) {
49046542Sarchie					proto = &protos[i];
49146542Sarchie					break;
49246542Sarchie				}
49346542Sarchie			}
49446542Sarchie			if (protos[i].name == NULL) {	/* generic handler */
49546542Sarchie				struct protoent *pe;
49646542Sarchie				u_long pnum;
49746542Sarchie				char *eptr;
49846542Sarchie
49946542Sarchie				/* Determine the IP protocol number */
50046542Sarchie				if ((pe = getprotobyname(optarg)) != NULL)
50146542Sarchie					pnum = pe->p_proto;
50246542Sarchie				else {
50346542Sarchie					pnum = strtoul(optarg, &eptr, 10);
50446542Sarchie					if (pnum > 0xff
50546542Sarchie					    || *optarg == '\0'
50646542Sarchie					    || *eptr != '\0') {
50746542Sarchie						Fprintf(stderr, "%s: unknown "
50846542Sarchie						    "protocol \"%s\"\n",
50946542Sarchie						    prog, optarg);
51046542Sarchie						exit(1);
51146542Sarchie					}
51246542Sarchie				}
51346542Sarchie				proto->num = pnum;
51446542Sarchie			}
51546542Sarchie			break;
51646542Sarchie
51718579Sfenner		case 'p':
51848221Sarchie			requestPort = atoi(optarg);
51948221Sarchie			if (requestPort <= 0) {
52018579Sfenner				Fprintf(stderr, "%s: port must be > 0\n", prog);
52118579Sfenner				exit(1);
52218579Sfenner			}
52318579Sfenner			break;
52418579Sfenner
52518579Sfenner		case 'q':
52618579Sfenner			nprobes = atoi(optarg);
52718579Sfenner			if (nprobes <= 0) {
52818579Sfenner				Fprintf(stderr, "%s: nprobes must be > 0\n",
52918579Sfenner				    prog);
53018579Sfenner				exit(1);
53118579Sfenner			}
53218579Sfenner			break;
53318579Sfenner
53418579Sfenner		case 'r':
53518579Sfenner			options |= SO_DONTROUTE;
53618579Sfenner			break;
53718579Sfenner
53818579Sfenner		case 's':
53918579Sfenner			/*
54018579Sfenner			 * set the ip source address of the outbound
54118579Sfenner			 * probe (e.g., on a multi-homed host).
54218579Sfenner			 */
54318579Sfenner			source = optarg;
54418579Sfenner			break;
54518579Sfenner
54618579Sfenner		case 't':
54718579Sfenner			tos = atoi(optarg);
54818579Sfenner			if (tos < 0 || tos > 255) {
54918579Sfenner				Fprintf(stderr, "%s: tos must be 0 to 255\n",
55018579Sfenner				    prog);
55118579Sfenner				exit(1);
55218579Sfenner			}
55318579Sfenner			break;
55418579Sfenner
55518579Sfenner		case 'v':
55618579Sfenner			++verbose;
55718579Sfenner			break;
55818579Sfenner
55918579Sfenner		case 'w':
56018579Sfenner			waittime = atoi(optarg);
56144086Sdes			if (waittime <= 1 || waittime >= 24L * 60 * 60) {
56244086Sdes				Fprintf(stderr,
56344086Sdes				    "%s: wait must be > 1 sec and < 1 day\n",
56418579Sfenner				    prog);
56518579Sfenner				exit(1);
56618579Sfenner			}
56718579Sfenner			break;
56818579Sfenner
56918579Sfenner		default:
57018579Sfenner			usage();
57118579Sfenner		}
57218579Sfenner
57348221Sarchie	/* Set requested port, if any, else default for this protocol */
57448221Sarchie	port = (requestPort != -1) ? requestPort : proto->port;
57548221Sarchie
57647071Sarchie	/* Check min vs. max TTL */
57747071Sarchie	if (min_ttl > max_ttl) {
57847071Sarchie		Fprintf(stderr, "%s: min ttl must be <= max ttl\n", prog);
57947071Sarchie		exit(1);
58047071Sarchie	}
58147071Sarchie
58218579Sfenner	/* Process destination and optional packet size */
58318579Sfenner	switch (argc - optind) {
58418579Sfenner
58518579Sfenner	case 2:
58618579Sfenner		packlen = atoi(argv[optind + 1]);
58718579Sfenner		/* Fall thorugh */
58818579Sfenner
58918579Sfenner	case 1:
59018579Sfenner		hostname = savestr(getsin(to, argv[optind]));
59118579Sfenner		break;
59218579Sfenner
59318579Sfenner	default:
59418579Sfenner		usage();
59518579Sfenner	}
59618579Sfenner
59718579Sfenner#ifdef HAVE_SETLINEBUF
59818579Sfenner	setlinebuf (stdout);
59918579Sfenner#else
60018579Sfenner	setvbuf(stdout, NULL, _IOLBF, 0);
60118579Sfenner#endif
60218579Sfenner
60318579Sfenner	if (lsrr > 0)
60418579Sfenner		optlen = (lsrr + 1) * sizeof(gwlist[0]);
60546542Sarchie	i = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
60618579Sfenner	if (packlen == 0)
60718579Sfenner		packlen = i;			/* minimum sized packet */
60818579Sfenner	else if (i > packlen || packlen > maxpacket) {
60918579Sfenner		Fprintf(stderr, "%s: packet size must be %d <= s <= %d\n",
61018579Sfenner		    prog, i, maxpacket);
61118579Sfenner		exit(1);
61218579Sfenner	}
61346542Sarchie	protlen = packlen - sizeof(*outip) - optlen;
61418579Sfenner
61518579Sfenner	outip = (struct ip *)malloc((unsigned)packlen);
61618579Sfenner	if (outip == NULL) {
61718579Sfenner		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
61818579Sfenner		exit(1);
61918579Sfenner	}
62018579Sfenner	memset((char *)outip, 0, packlen);
62118579Sfenner
62218579Sfenner	outip->ip_v = IPVERSION;
62318579Sfenner	outip->ip_tos = tos;
62418579Sfenner#ifdef BYTESWAP_IP_LEN
62518579Sfenner	outip->ip_len = htons(packlen);
62618579Sfenner#else
62718579Sfenner	outip->ip_len = packlen;
62818579Sfenner#endif
62946542Sarchie	outip->ip_p = proto->num;
63046542Sarchie	outprot = (u_char *)(outip + 1);
63118579Sfenner#ifdef HAVE_RAW_OPTIONS
63218579Sfenner	if (lsrr > 0) {
63318579Sfenner		register u_char *optlist;
63418579Sfenner
63546542Sarchie		optlist = (u_char *)outprot;
63646542Sarchie		(u_char *)outprot += optlen;
63718579Sfenner
63818579Sfenner		/* final hop */
63918579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
64018579Sfenner
64118579Sfenner		outip->ip_dst.s_addr = gwlist[0];
64218579Sfenner
64318579Sfenner		/* force 4 byte alignment */
64418579Sfenner		optlist[0] = IPOPT_NOP;
64518579Sfenner		/* loose source route option */
64618579Sfenner		optlist[1] = IPOPT_LSRR;
64718579Sfenner		i = lsrr * sizeof(gwlist[0]);
64818579Sfenner		optlist[2] = i + 3;
64918579Sfenner		/* Pointer to LSRR addresses */
65018579Sfenner		optlist[3] = IPOPT_MINOFF;
65118579Sfenner		memcpy(optlist + 4, gwlist + 1, i);
65218579Sfenner	} else
65318579Sfenner#endif
65418579Sfenner		outip->ip_dst = to->sin_addr;
65518579Sfenner
65646542Sarchie	outip->ip_hl = ((u_char *)outprot - (u_char *)outip) >> 2;
65718579Sfenner
65818579Sfenner	ident = (getpid() & 0xffff) | 0x8000;
65918579Sfenner
66018583Sfenner	if (pe == NULL) {
66118579Sfenner		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
66218579Sfenner		exit(1);
66318579Sfenner	}
66418583Sfenner	if (s < 0) {
66518583Sfenner		errno = sockerrno;
66618579Sfenner		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
66718579Sfenner		exit(1);
66818579Sfenner	}
66918579Sfenner	if (options & SO_DEBUG)
67018579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
67118579Sfenner		    sizeof(on));
67218579Sfenner	if (options & SO_DONTROUTE)
67318579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
67418579Sfenner		    sizeof(on));
67518579Sfenner
67658804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
67758804Sshin	if (setpolicy(s, "in bypass") < 0)
67866809Skris		errx(1, "%s", ipsec_strerror());
67958804Sshin
68058804Sshin	if (setpolicy(s, "out bypass") < 0)
68166809Skris		errx(1, "%s", ipsec_strerror());
68258804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
68358804Sshin
68418583Sfenner	if (sndsock < 0) {
68518583Sfenner		errno = sockerrno;
68618579Sfenner		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
68718579Sfenner		exit(1);
68818579Sfenner	}
68918579Sfenner
69018579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
69118579Sfenner	if (lsrr > 0) {
69218579Sfenner		u_char optlist[MAX_IPOPTLEN];
69318579Sfenner
69418579Sfenner		cp = "ip";
69518579Sfenner		if ((pe = getprotobyname(cp)) == NULL) {
69618579Sfenner			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
69718579Sfenner			exit(1);
69818579Sfenner		}
69918579Sfenner
70018579Sfenner		/* final hop */
70118579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
70218579Sfenner		++lsrr;
70318579Sfenner
70418579Sfenner		/* force 4 byte alignment */
70518579Sfenner		optlist[0] = IPOPT_NOP;
70618579Sfenner		/* loose source route option */
70718579Sfenner		optlist[1] = IPOPT_LSRR;
70818579Sfenner		i = lsrr * sizeof(gwlist[0]);
70918579Sfenner		optlist[2] = i + 3;
71018579Sfenner		/* Pointer to LSRR addresses */
71118579Sfenner		optlist[3] = IPOPT_MINOFF;
71218579Sfenner		memcpy(optlist + 4, gwlist, i);
71318579Sfenner
71418579Sfenner		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist,
71518579Sfenner		    i + sizeof(gwlist[0]))) < 0) {
71618579Sfenner			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
71718579Sfenner			    prog, strerror(errno));
71818579Sfenner			exit(1);
71918579Sfenner		    }
72018579Sfenner	}
72118579Sfenner#endif
72218579Sfenner
72318579Sfenner#ifdef SO_SNDBUF
72418579Sfenner	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
72518579Sfenner	    sizeof(packlen)) < 0) {
72618579Sfenner		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
72718579Sfenner		exit(1);
72818579Sfenner	}
72918579Sfenner#endif
73018579Sfenner#ifdef IP_HDRINCL
73118579Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
73218579Sfenner	    sizeof(on)) < 0) {
73318579Sfenner		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
73418579Sfenner		exit(1);
73518579Sfenner	}
73618579Sfenner#endif
73718579Sfenner	if (options & SO_DEBUG)
73818579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
73918579Sfenner		    sizeof(on));
74018579Sfenner	if (options & SO_DONTROUTE)
74118579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
74218579Sfenner		    sizeof(on));
74318579Sfenner
74418579Sfenner	if (source != NULL) {
74518579Sfenner		source = savestr(getsin(&from, source));
74618579Sfenner		outip->ip_src = from.sin_addr;
74718579Sfenner#ifndef IP_HDRINCL
74818579Sfenner		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
74918579Sfenner			Fprintf(stderr, "%s: bind: %s\n",
75018579Sfenner			    prog, strerror(errno));
75118579Sfenner			exit (1);
75218579Sfenner		}
75318579Sfenner#endif
75418579Sfenner	}
75518579Sfenner
75658804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
75758804Sshin	if (setpolicy(sndsock, "in bypass") < 0)
75866809Skris		errx(1, "%s", ipsec_strerror());
75958804Sshin
76058804Sshin	if (setpolicy(sndsock, "out bypass") < 0)
76166809Skris		errx(1, "%s", ipsec_strerror());
76258804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
76358804Sshin
76418579Sfenner	Fprintf(stderr, "%s to %s (%s)",
76518579Sfenner	    prog, hostname, inet_ntoa(to->sin_addr));
76618579Sfenner	if (source)
76718579Sfenner		Fprintf(stderr, " from %s", source);
76818579Sfenner	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
76918579Sfenner	(void)fflush(stderr);
77018579Sfenner
77147071Sarchie	for (ttl = min_ttl; ttl <= max_ttl; ++ttl) {
77218579Sfenner		u_int32_t lastaddr = 0;
77318579Sfenner		int got_there = 0;
77418579Sfenner		int unreachable = 0;
77518695Ssef		int loss;
77618579Sfenner
77718579Sfenner		Printf("%2d ", ttl);
77818695Ssef		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
77918579Sfenner			register int cc;
78018579Sfenner			struct timeval t1, t2;
78118579Sfenner			struct timezone tz;
78218579Sfenner			register struct ip *ip;
78346542Sarchie			struct outdata outdata;
78418579Sfenner
78546542Sarchie			/* Prepare outgoing data */
78646542Sarchie			outdata.seq = ++seq;
78746542Sarchie			outdata.ttl = ttl;
78846542Sarchie
78946542Sarchie			/* Avoid alignment problems by copying bytewise: */
79018579Sfenner			(void)gettimeofday(&t1, &tz);
79146542Sarchie			memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
79246542Sarchie
79346542Sarchie			/* Finalize and send packet */
79446542Sarchie			(*proto->prepare)(&outdata);
79546542Sarchie			send_probe(seq, ttl);
79646542Sarchie
79746542Sarchie			/* Wait for a reply */
79818579Sfenner			while ((cc = wait_for_reply(s, &from, &t1)) != 0) {
79918583Sfenner				double T;
80018583Sfenner				int precis;
80118583Sfenner
80218579Sfenner				(void)gettimeofday(&t2, &tz);
80318579Sfenner				i = packet_ok(packet, cc, &from, seq);
80418579Sfenner				/* Skip short packet */
80518579Sfenner				if (i == 0)
80618579Sfenner					continue;
80718579Sfenner				if (from.sin_addr.s_addr != lastaddr) {
80818579Sfenner					print(packet, cc, &from);
80918579Sfenner					lastaddr = from.sin_addr.s_addr;
81018579Sfenner				}
81118583Sfenner				T = deltaT(&t1, &t2);
81218583Sfenner#ifdef SANE_PRECISION
81318583Sfenner				if (T >= 1000.0)
81418583Sfenner					precis = 0;
81518583Sfenner				else if (T >= 100.0)
81618583Sfenner					precis = 1;
81718583Sfenner				else if (T >= 10.0)
81818583Sfenner					precis = 2;
81918583Sfenner				else
82018583Sfenner#endif
82118583Sfenner					precis = 3;
82218583Sfenner				Printf("  %.*f ms", precis, T);
82318579Sfenner				/* time exceeded in transit */
82418579Sfenner				if (i == -1)
82518579Sfenner					break;
82618579Sfenner				code = i - 1;
82718579Sfenner				switch (code) {
82818579Sfenner
82918579Sfenner				case ICMP_UNREACH_PORT:
83018579Sfenner#ifndef ARCHAIC
83118579Sfenner					ip = (struct ip *)packet;
83218579Sfenner					if (ip->ip_ttl <= 1)
83318579Sfenner						Printf(" !");
83418579Sfenner#endif
83518579Sfenner					++got_there;
83618579Sfenner					break;
83718579Sfenner
83818579Sfenner				case ICMP_UNREACH_NET:
83918579Sfenner					++unreachable;
84018579Sfenner					Printf(" !N");
84118579Sfenner					break;
84218579Sfenner
84318579Sfenner				case ICMP_UNREACH_HOST:
84418579Sfenner					++unreachable;
84518579Sfenner					Printf(" !H");
84618579Sfenner					break;
84718579Sfenner
84818579Sfenner				case ICMP_UNREACH_PROTOCOL:
84918579Sfenner					++got_there;
85018579Sfenner					Printf(" !P");
85118579Sfenner					break;
85218579Sfenner
85318579Sfenner				case ICMP_UNREACH_NEEDFRAG:
85418579Sfenner					++unreachable;
85518579Sfenner					Printf(" !F");
85618579Sfenner					break;
85718579Sfenner
85818579Sfenner				case ICMP_UNREACH_SRCFAIL:
85918579Sfenner					++unreachable;
86018579Sfenner					Printf(" !S");
86118579Sfenner					break;
86218579Sfenner
86318579Sfenner/* rfc1716 */
86418579Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB
86518579Sfenner#define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
86618579Sfenner#endif
86718579Sfenner				case ICMP_UNREACH_FILTER_PROHIB:
86818579Sfenner					++unreachable;
86918579Sfenner					Printf(" !X");
87018579Sfenner					break;
87118579Sfenner
87218579Sfenner				default:
87318579Sfenner					++unreachable;
87418579Sfenner					Printf(" !<%d>", code);
87518579Sfenner					break;
87618579Sfenner				}
87718579Sfenner				break;
87818579Sfenner			}
87918695Ssef			if (cc == 0) {
88018695Ssef				loss++;
88118579Sfenner				Printf(" *");
88218695Ssef			}
88318579Sfenner			(void)fflush(stdout);
88418579Sfenner		}
88518803Ssef		if (sump) {
88618811Ssef			Printf(" (%d%% loss)", (loss * 100) / nprobes);
88718803Ssef		}
88818579Sfenner		putchar('\n');
88918579Sfenner		if (got_there ||
89018579Sfenner		    (unreachable > 0 && unreachable >= nprobes - 1))
89118579Sfenner			break;
89218579Sfenner	}
89318579Sfenner	exit(0);
89418579Sfenner}
89518579Sfenner
89618579Sfennerint
89718579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp,
89818579Sfenner    register struct timeval *tp)
89918579Sfenner{
90066810Skris	fd_set *fdsp;
90166810Skris	size_t nfds;
90218579Sfenner	struct timeval now, wait;
90318579Sfenner	struct timezone tz;
90418579Sfenner	register int cc = 0;
90544086Sdes	register int error;
90618579Sfenner	int fromlen = sizeof(*fromp);
90718579Sfenner
90866810Skris	nfds = howmany(sock + 1, NFDBITS);
90966810Skris	if ((fdsp = malloc(nfds)) == NULL)
91066810Skris		err(1, "malloc");
91166810Skris	memset(fdsp, 0, nfds);
91266810Skris	FD_SET(sock, fdsp);
91318579Sfenner
91418579Sfenner	wait.tv_sec = tp->tv_sec + waittime;
91518579Sfenner	wait.tv_usec = tp->tv_usec;
91618579Sfenner	(void)gettimeofday(&now, &tz);
91718579Sfenner	tvsub(&wait, &now);
91844086Sdes	if (wait.tv_sec < 0) {
91944086Sdes		wait.tv_sec = 0;
92044086Sdes		wait.tv_usec = 1;
92144086Sdes	}
92218579Sfenner
92366810Skris	error = select(sock + 1, fdsp, NULL, NULL, &wait);
92444086Sdes	if (error == -1 && errno == EINVAL) {
92544086Sdes		Fprintf(stderr, "%s: botched select() args\n", prog);
92644086Sdes		exit(1);
92744086Sdes	}
92844086Sdes	if (error > 0)
92918579Sfenner		cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
93018579Sfenner			    (struct sockaddr *)fromp, &fromlen);
93118579Sfenner
93266810Skris	free(fdsp);
93318579Sfenner	return(cc);
93418579Sfenner}
93518579Sfenner
93658804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
93758804Sshinint
93858804Sshinsetpolicy(so, policy)
93958804Sshin	int so;
94058804Sshin	char *policy;
94158804Sshin{
94258804Sshin	char *buf;
94358804Sshin
94458804Sshin	buf = ipsec_set_policy(policy, strlen(policy));
94558804Sshin	if (buf == NULL) {
94666809Skris		warnx("%s", ipsec_strerror());
94758804Sshin		return -1;
94858804Sshin	}
94958804Sshin	(void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
95058804Sshin		buf, ipsec_get_policylen(buf));
95158804Sshin
95258804Sshin	free(buf);
95358804Sshin
95458804Sshin	return 0;
95558804Sshin}
95658804Sshin#endif
95758804Sshin
95818579Sfennervoid
95946542Sarchiesend_probe(int seq, int ttl)
96018579Sfenner{
96118579Sfenner	register int i;
96218579Sfenner
96318579Sfenner	outip->ip_ttl = ttl;
96418579Sfenner	outip->ip_id = htons(ident + seq);
96518579Sfenner
96618579Sfenner	i = sendto(sndsock, (char *)outip, packlen, 0, &whereto,
96718579Sfenner		   sizeof(whereto));
96818579Sfenner	if (i < 0 || i != packlen)  {
96918579Sfenner		if (i < 0)
97018579Sfenner			Fprintf(stderr, "%s: sendto: %s\n",
97118579Sfenner			    prog, strerror(errno));
97218579Sfenner		Printf("%s: wrote %s %d chars, ret=%d\n",
97318579Sfenner		    prog, hostname, packlen, i);
97418579Sfenner		(void)fflush(stdout);
97518579Sfenner	}
97618579Sfenner}
97718579Sfenner
97818579Sfennerdouble
97918579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p)
98018579Sfenner{
98118579Sfenner	register double dt;
98218579Sfenner
98318579Sfenner	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
98418579Sfenner	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
98518579Sfenner	return (dt);
98618579Sfenner}
98718579Sfenner
98818579Sfenner/*
98918579Sfenner * Convert an ICMP "type" field to a printable string.
99018579Sfenner */
99118579Sfennerchar *
99218579Sfennerpr_type(register u_char t)
99318579Sfenner{
99418579Sfenner	static char *ttab[] = {
99518579Sfenner	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
99618579Sfenner	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
99718579Sfenner	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
99818579Sfenner	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
99918579Sfenner	"Info Reply"
100018579Sfenner	};
100118579Sfenner
100218579Sfenner	if (t > 16)
100318579Sfenner		return("OUT-OF-RANGE");
100418579Sfenner
100518579Sfenner	return(ttab[t]);
100618579Sfenner}
100718579Sfenner
100818579Sfennerint
100918579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
101018579Sfenner    register int seq)
101118579Sfenner{
101218579Sfenner	register struct icmp *icp;
101318579Sfenner	register u_char type, code;
101418579Sfenner	register int hlen;
101518579Sfenner#ifndef ARCHAIC
101618579Sfenner	register struct ip *ip;
101718579Sfenner
101818579Sfenner	ip = (struct ip *) buf;
101918579Sfenner	hlen = ip->ip_hl << 2;
102018579Sfenner	if (cc < hlen + ICMP_MINLEN) {
102118579Sfenner		if (verbose)
102218579Sfenner			Printf("packet too short (%d bytes) from %s\n", cc,
102318579Sfenner				inet_ntoa(from->sin_addr));
102418579Sfenner		return (0);
102518579Sfenner	}
102618579Sfenner	cc -= hlen;
102718579Sfenner	icp = (struct icmp *)(buf + hlen);
102818579Sfenner#else
102918579Sfenner	icp = (struct icmp *)buf;
103018579Sfenner#endif
103118579Sfenner	type = icp->icmp_type;
103218579Sfenner	code = icp->icmp_code;
103318579Sfenner	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
103418579Sfenner	    type == ICMP_UNREACH) {
103518579Sfenner		struct ip *hip;
103646542Sarchie		u_char *inner;
103718579Sfenner
103818579Sfenner		hip = &icp->icmp_ip;
103918579Sfenner		hlen = hip->ip_hl << 2;
104046542Sarchie		inner = (u_char *)((u_char *)hip + hlen);
104146542Sarchie		if (hlen + 12 <= cc
104246542Sarchie		    && hip->ip_p == proto->num
104346542Sarchie		    && (*proto->check)(inner, seq))
104418579Sfenner			return (type == ICMP_TIMXCEED ? -1 : code + 1);
104518579Sfenner	}
104618579Sfenner#ifndef ARCHAIC
104718579Sfenner	if (verbose) {
104818579Sfenner		register int i;
104918579Sfenner		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
105018579Sfenner
105118579Sfenner		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
105218579Sfenner		Printf("%s: icmp type %d (%s) code %d\n",
105318579Sfenner		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
105418579Sfenner		for (i = 4; i < cc ; i += sizeof(*lp))
105518579Sfenner			Printf("%2d: x%8.8x\n", i, *lp++);
105618579Sfenner	}
105718579Sfenner#endif
105818579Sfenner	return(0);
105918579Sfenner}
106018579Sfenner
106146542Sarchievoid
106246542Sarchieudp_prep(struct outdata *outdata)
106346542Sarchie{
106446542Sarchie	struct udphdr *const udp = (struct udphdr *) outprot;
106518579Sfenner
106646542Sarchie	udp->uh_sport = htons(ident);
106746542Sarchie	udp->uh_dport = htons(port + outdata->seq);
106846542Sarchie	udp->uh_ulen = htons((u_short)protlen);
106946542Sarchie}
107046542Sarchie
107146542Sarchieint
107246542Sarchieudp_check(const u_char *data, int seq)
107346542Sarchie{
107446542Sarchie	struct udphdr *const udp = (struct udphdr *) data;
107546542Sarchie
107646542Sarchie	return (ntohs(udp->uh_sport) == ident
107746542Sarchie	    && ntohs(udp->uh_dport) == port + seq);
107846542Sarchie}
107946542Sarchie
108018579Sfennervoid
108146542Sarchietcp_prep(struct outdata *outdata)
108246542Sarchie{
108346542Sarchie	struct tcphdr *const tcp = (struct tcphdr *) outprot;
108446542Sarchie
108546542Sarchie	tcp->th_sport = htons(ident);
108646542Sarchie	tcp->th_dport = htons(port + outdata->seq);
108746542Sarchie	tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
108846542Sarchie	tcp->th_ack = 0;
108946542Sarchie	tcp->th_off = 5;
109046542Sarchie	tcp->th_flags = TH_SYN;
109146542Sarchie}
109246542Sarchie
109346542Sarchieint
109446542Sarchietcp_check(const u_char *data, int seq)
109546542Sarchie{
109646542Sarchie	struct tcphdr *const tcp = (struct tcphdr *) data;
109746542Sarchie
109846542Sarchie	return (ntohs(tcp->th_sport) == ident
109946542Sarchie	    && ntohs(tcp->th_dport) == port + seq);
110046542Sarchie}
110146542Sarchie
110246542Sarchievoid
110346542Sarchiegre_prep(struct outdata *outdata)
110446542Sarchie{
110546542Sarchie	struct grehdr *const gre = (struct grehdr *) outprot;
110646542Sarchie
110746542Sarchie	gre->flags = htons(0x2001);
110846542Sarchie	gre->proto = htons(port);
110946542Sarchie	gre->length = 0;
111046542Sarchie	gre->callId = htons(ident + outdata->seq);
111146542Sarchie}
111246542Sarchie
111346542Sarchieint
111446542Sarchiegre_check(const u_char *data, int seq)
111546542Sarchie{
111646542Sarchie	struct grehdr *const gre = (struct grehdr *) data;
111746542Sarchie
111846542Sarchie	return(ntohs(gre->proto) == port
111946542Sarchie	    && ntohs(gre->callId) == ident + seq);
112046542Sarchie}
112146542Sarchie
112246542Sarchievoid
112346542Sarchiegen_prep(struct outdata *outdata)
112446542Sarchie{
112546542Sarchie	u_int16_t *const ptr;
112646542Sarchie
112746542Sarchie	ptr[0] = htons(ident);
112846542Sarchie	ptr[1] = htons(port + outdata->seq);
112946542Sarchie}
113046542Sarchie
113146542Sarchieint
113246542Sarchiegen_check(const u_char *data, int seq)
113346542Sarchie{
113446542Sarchie	u_int16_t *const ptr = (u_int16_t *) data;
113546542Sarchie
113646542Sarchie	return(ntohs(ptr[0]) == ident
113746542Sarchie	    && ntohs(ptr[1]) == port + seq);
113846542Sarchie}
113946542Sarchie
114046542Sarchievoid
114118579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from)
114218579Sfenner{
114318579Sfenner	register struct ip *ip;
114418579Sfenner	register int hlen;
114518579Sfenner
114618579Sfenner	ip = (struct ip *) buf;
114718579Sfenner	hlen = ip->ip_hl << 2;
114818579Sfenner	cc -= hlen;
114918579Sfenner
115018579Sfenner	if (nflag)
115118579Sfenner		Printf(" %s", inet_ntoa(from->sin_addr));
115218579Sfenner	else
115318579Sfenner		Printf(" %s (%s)", inetname(from->sin_addr),
115418579Sfenner		    inet_ntoa(from->sin_addr));
115518579Sfenner
115618579Sfenner	if (verbose)
115718579Sfenner		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
115818579Sfenner}
115918579Sfenner
116018579Sfenner
116118579Sfenner#ifdef notyet
116218579Sfenner/*
116318579Sfenner * Checksum routine for Internet Protocol family headers (C Version)
116418579Sfenner */
116518579Sfennerin_cksum(register u_short *addr, register int len)
116618579Sfenner{
116718579Sfenner	register int nleft = len;
116818579Sfenner	register u_short *w = addr;
116918579Sfenner	register u_short answer;
117018579Sfenner	register int sum = 0;
117118579Sfenner
117218579Sfenner	/*
117318579Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
117418579Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
117518579Sfenner	 *  back all the carry bits from the top 16 bits into the lower
117618579Sfenner	 *  16 bits.
117718579Sfenner	 */
117818579Sfenner	while (nleft > 1)  {
117918579Sfenner		sum += *w++;
118018579Sfenner		nleft -= 2;
118118579Sfenner	}
118218579Sfenner
118318579Sfenner	/* mop up an odd byte, if necessary */
118418579Sfenner	if (nleft == 1)
118518579Sfenner		sum += *(u_char *)w;
118618579Sfenner
118718579Sfenner	/*
118818579Sfenner	 * add back carry outs from top 16 bits to low 16 bits
118918579Sfenner	 */
119018579Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
119118579Sfenner	sum += (sum >> 16);			/* add carry */
119218579Sfenner	answer = ~sum;				/* truncate to 16 bits */
119318579Sfenner	return (answer);
119418579Sfenner}
119518579Sfenner#endif
119618579Sfenner
119718579Sfenner/*
119818579Sfenner * Subtract 2 timeval structs:  out = out - in.
119944086Sdes * Out is assumed to be within about LONG_MAX seconds of in.
120018579Sfenner */
120118579Sfennervoid
120218579Sfennertvsub(register struct timeval *out, register struct timeval *in)
120318579Sfenner{
120418579Sfenner
120518579Sfenner	if ((out->tv_usec -= in->tv_usec) < 0)   {
120618579Sfenner		--out->tv_sec;
120718579Sfenner		out->tv_usec += 1000000;
120818579Sfenner	}
120918579Sfenner	out->tv_sec -= in->tv_sec;
121018579Sfenner}
121118579Sfenner
121218579Sfenner/*
121318579Sfenner * Construct an Internet address representation.
121418579Sfenner * If the nflag has been supplied, give
121518579Sfenner * numeric value, otherwise try for symbolic name.
121618579Sfenner */
121718579Sfennerchar *
121818579Sfennerinetname(struct in_addr in)
121918579Sfenner{
122018579Sfenner	register char *cp;
122118579Sfenner	register struct hostent *hp;
122218579Sfenner	static int first = 1;
122318579Sfenner	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
122418579Sfenner
122518579Sfenner	if (first && !nflag) {
122618579Sfenner		first = 0;
122718579Sfenner		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
122818579Sfenner		    (cp = strchr(domain, '.')) != NULL) {
122918579Sfenner			(void)strncpy(domain, cp + 1, sizeof(domain) - 1);
123018579Sfenner			domain[sizeof(domain) - 1] = '\0';
123118579Sfenner		} else
123218579Sfenner			domain[0] = '\0';
123318579Sfenner	}
123418579Sfenner	if (!nflag && in.s_addr != INADDR_ANY) {
123518579Sfenner		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
123618579Sfenner		if (hp != NULL) {
123718579Sfenner			if ((cp = strchr(hp->h_name, '.')) != NULL &&
123818579Sfenner			    strcmp(cp + 1, domain) == 0)
123918579Sfenner				*cp = '\0';
124018579Sfenner			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
124118579Sfenner			line[sizeof(line) - 1] = '\0';
124218579Sfenner			return (line);
124318579Sfenner		}
124418579Sfenner	}
124518579Sfenner	return (inet_ntoa(in));
124618579Sfenner}
124718579Sfenner
124818579Sfennerchar *
124918579Sfennergetaddr(register u_int32_t *ap, register char *hostname)
125018579Sfenner{
125118579Sfenner	register struct hostent *hp;
125218579Sfenner
125318579Sfenner	*ap = inet_addr(hostname);
125418579Sfenner	if ((int32_t)*ap != -1)
125518579Sfenner		return (hostname);
125618579Sfenner
125718579Sfenner	hp = gethostbyname(hostname);
125818579Sfenner	if (hp == NULL) {
125918579Sfenner		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
126018579Sfenner		exit(1);
126118579Sfenner	}
126218579Sfenner	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
126318579Sfenner		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
126418579Sfenner		exit(1);
126518579Sfenner	}
126618579Sfenner	memcpy((caddr_t)ap, hp->h_addr, hp->h_length);
126718579Sfenner	return (hp->h_name);
126818579Sfenner}
126918579Sfenner
127018579Sfennerchar *
127118579Sfennergetsin(register struct sockaddr_in *sin, register char *hostname)
127218579Sfenner{
127318579Sfenner
127418579Sfenner	memset(sin, 0, sizeof(*sin));
127518579Sfenner	sin->sin_family = AF_INET;
127618579Sfenner	return (getaddr((u_int32_t *)&sin->sin_addr.s_addr, hostname));
127718579Sfenner}
127818579Sfenner
127918579Sfennerchar *
128018579Sfennersavestr(register const char *str)
128118579Sfenner{
128218579Sfenner	register char *cp;
128318579Sfenner
128418579Sfenner	cp = strdup(str);
128518579Sfenner	if (cp == NULL) {
128618579Sfenner		Fprintf(stderr, "%s: strdup: %s\n", prog, strerror(errno));
128718579Sfenner		exit(1);
128818579Sfenner	}
128918579Sfenner	return (cp);
129018579Sfenner}
129118579Sfenner
129267682Sobrienvoid
129318579Sfennerusage(void)
129418579Sfenner{
129518579Sfenner	extern char version[];
129618579Sfenner
129718579Sfenner	Fprintf(stderr, "Version %s\n", version);
129862786Sghelmer	Fprintf(stderr, "Usage: %s [-Sdnrv] [-w wait] [-m max_ttl] [-M min_ttl] \
129947071Sarchie[-P proto]\n\t [-p port#] [-q nqueries] [-t tos] [-s src_addr] [-g gateway] \
130047071Sarchie\n\t host [data_size]\n", prog);
130118579Sfenner	exit(1);
130218579Sfenner}
1303