traceroute.c revision 176428
118579Sfenner/*
2100787Sfenner * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
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[] =
24100787Sfenner    "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
2518579SfennerThe Regents of the University of California.  All rights reserved.\n";
2658835Sshin#if 0
2718579Sfennerstatic const char rcsid[] =
28100787Sfenner    "@(#)$Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp $ (LBL)";
2918579Sfenner#endif
3058835Sshinstatic const char rcsid[] =
3158835Sshin    "$FreeBSD: head/contrib/traceroute/traceroute.c 176428 2008-02-20 23:29:53Z rpaulo $";
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>
223100787Sfenner#include <netinet/udp_var.h>
22446542Sarchie#include <netinet/tcp.h>
225100789Sfenner#include <netinet/tcpip.h>
22618579Sfenner
22718579Sfenner#include <arpa/inet.h>
22818579Sfenner
22958804Sshin#ifdef	IPSEC
23058804Sshin#include <net/route.h>
231171135Sgnn#include <netipsec/ipsec.h>	/* XXX */
23258804Sshin#endif	/* IPSEC */
23358804Sshin
23418579Sfenner#include <ctype.h>
235100787Sfenner#include <err.h>
23618579Sfenner#include <errno.h>
237100787Sfenner#include <fcntl.h>
23818579Sfenner#ifdef HAVE_MALLOC_H
23918579Sfenner#include <malloc.h>
24018579Sfenner#endif
24118579Sfenner#include <memory.h>
24218579Sfenner#include <netdb.h>
24318579Sfenner#include <stdio.h>
24418579Sfenner#include <stdlib.h>
24518579Sfenner#include <string.h>
24618579Sfenner#include <unistd.h>
24718579Sfenner
24818579Sfenner#include "gnuc.h"
24918579Sfenner#ifdef HAVE_OS_PROTO_H
25018579Sfenner#include "os-proto.h"
25118579Sfenner#endif
25218579Sfenner
253100787Sfenner/* rfc1716 */
254100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB
255100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
256100787Sfenner#endif
257100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE
258100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
259100787Sfenner#endif
260100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
261100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
262100787Sfenner#endif
263100787Sfenner
264100787Sfenner#include "findsaddr.h"
265100787Sfenner#include "ifaddrlist.h"
266176428Srpaulo#include "as.h"
267100787Sfenner#include "traceroute.h"
268100787Sfenner
26918579Sfenner/* Maximum number of gateways (include room for one noop) */
27018579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
27118579Sfenner
27218579Sfenner#ifndef MAXHOSTNAMELEN
27318579Sfenner#define MAXHOSTNAMELEN	64
27418579Sfenner#endif
27518579Sfenner
27618579Sfenner#define Fprintf (void)fprintf
27718579Sfenner#define Printf (void)printf
27818579Sfenner
27946542Sarchie/* What a GRE packet header looks like */
28046542Sarchiestruct grehdr {
28146542Sarchie	u_int16_t   flags;
28246542Sarchie	u_int16_t   proto;
28346542Sarchie	u_int16_t   length;	/* PPTP version of these fields */
28446542Sarchie	u_int16_t   callId;
28546542Sarchie};
28646542Sarchie#ifndef IPPROTO_GRE
28746542Sarchie#define IPPROTO_GRE	47
28846542Sarchie#endif
28946542Sarchie
29046542Sarchie/* For GRE, we prepare what looks like a PPTP packet */
29146542Sarchie#define GRE_PPTP_PROTO	0x880b
29246542Sarchie
293100787Sfenner/* Host name and address list */
294100787Sfennerstruct hostinfo {
295100787Sfenner	char *name;
296100787Sfenner	int n;
297100787Sfenner	u_int32_t *addrs;
298100787Sfenner};
299100787Sfenner
30018579Sfenner/* Data section of the probe packet */
30118579Sfennerstruct outdata {
30218579Sfenner	u_char seq;		/* sequence number of this packet */
30318579Sfenner	u_char ttl;		/* ttl packet left with */
30418579Sfenner	struct timeval tv;	/* time packet left */
30518579Sfenner};
30618579Sfenner
307100787Sfenner#ifndef HAVE_ICMP_NEXTMTU
308100787Sfenner/* Path MTU Discovery (RFC1191) */
309100787Sfennerstruct my_pmtu {
310100787Sfenner	u_short ipm_void;
311100787Sfenner	u_short ipm_nextmtu;
31246542Sarchie};
313100787Sfenner#endif
31446542Sarchie
31518579Sfenneru_char	packet[512];		/* last inbound (icmp) packet */
31618579Sfenner
31746542Sarchiestruct ip *outip;		/* last output ip packet */
318100787Sfenneru_char *outp;		/* last output inner protocol packet */
31918579Sfenner
320163387Sdwmalonestruct ip *hip = NULL;		/* Quoted IP header */
321163387Sdwmaloneint hiplen = 0;
322163387Sdwmalone
32318579Sfenner/* loose source route gateway list (including room for final destination) */
32418579Sfenneru_int32_t gwlist[NGATEWAYS + 1];
32518579Sfenner
32618579Sfennerint s;				/* receive (icmp) socket file descriptor */
32718579Sfennerint sndsock;			/* send (udp) socket file descriptor */
32818579Sfenner
32918579Sfennerstruct sockaddr whereto;	/* Who to try to reach */
330100787Sfennerstruct sockaddr wherefrom;	/* Who we are */
33118579Sfennerint packlen;			/* total length of packet */
33246542Sarchieint protlen;			/* length of protocol part of packet */
333100787Sfennerint minpacket;			/* min ip packet size */
33418579Sfennerint maxpacket = 32 * 1024;	/* max ip packet size */
335100787Sfennerint pmtu;			/* Path MTU Discovery (RFC1191) */
336100787Sfenneru_int pausemsecs;
33718579Sfenner
33818579Sfennerchar *prog;
33918579Sfennerchar *source;
34018579Sfennerchar *hostname;
341100787Sfennerchar *device;
342100787Sfennerstatic const char devnull[] = "/dev/null";
34318579Sfenner
344163387Sdwmaloneint nprobes = -1;
34577816Sruint max_ttl;
346100787Sfennerint first_ttl = 1;
34718579Sfenneru_short ident;
34846542Sarchieu_short port;			/* protocol specific base "port" */
34918579Sfenner
35018579Sfennerint options;			/* socket options */
35118579Sfennerint verbose;
35218579Sfennerint waittime = 5;		/* time to wait for response (in seconds) */
35318579Sfennerint nflag;			/* print addresses numerically */
354176428Srpauloint as_path;			/* print as numbers for each hop */
355176428Srpaulochar *as_server = NULL;
356176428Srpaulovoid *asn;
357100787Sfenner#ifdef CANT_HACK_IPCKSUM
358100787Sfennerint doipcksum = 0;		/* don't calculate ip checksums by default */
359100787Sfenner#else
360100787Sfennerint doipcksum = 1;		/* calculate ip checksums by default */
361100787Sfenner#endif
362100787Sfennerint optlen;			/* length of ip options */
363158424Scjcint fixedPort = 0;		/* Use fixed destination port for TCP and UDP */
364163387Sdwmaloneint printdiff = 0;		/* Print the difference between sent and quoted */
36518579Sfenner
36618579Sfennerextern int optind;
36718579Sfennerextern int opterr;
36818579Sfennerextern char *optarg;
36918579Sfenner
37018579Sfenner/* Forwards */
37118579Sfennerdouble	deltaT(struct timeval *, struct timeval *);
372100787Sfennervoid	freehostinfo(struct hostinfo *);
373100787Sfennervoid	getaddr(u_int32_t *, char *);
374100787Sfennerstruct	hostinfo *gethostinfo(char *);
375100535Sfenneru_short	in_cksum(u_short *, int);
37618579Sfennerchar	*inetname(struct in_addr);
37718579Sfennerint	main(int, char **);
378100789Sfenneru_short p_cksum(struct ip *, u_short *, int);
37918579Sfennerint	packet_ok(u_char *, int, struct sockaddr_in *, int);
38018579Sfennerchar	*pr_type(u_char);
38118579Sfennervoid	print(u_char *, int, struct sockaddr_in *);
38258804Sshin#ifdef	IPSEC
38358804Sshinint	setpolicy __P((int so, char *policy));
38458804Sshin#endif
38546542Sarchievoid	send_probe(int, int);
386100787Sfennerstruct outproto *setproto(char *);
387100787Sfennerint	str2val(const char *, const char *, int, int);
38818579Sfennervoid	tvsub(struct timeval *, struct timeval *);
38967682Sobrienvoid usage(void);
390100787Sfennerint	wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
391163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int);
392100787Sfenner#ifndef HAVE_USLEEP
393100787Sfennerint	usleep(u_int);
394100787Sfenner#endif
39518579Sfenner
39646542Sarchievoid	udp_prep(struct outdata *);
39746542Sarchieint	udp_check(const u_char *, int);
39846542Sarchievoid	tcp_prep(struct outdata *);
39946542Sarchieint	tcp_check(const u_char *, int);
40046542Sarchievoid	gre_prep(struct outdata *);
40146542Sarchieint	gre_check(const u_char *, int);
40246542Sarchievoid	gen_prep(struct outdata *);
40346542Sarchieint	gen_check(const u_char *, int);
404100535Sfennervoid	icmp_prep(struct outdata *);
405100535Sfennerint	icmp_check(const u_char *, int);
40646542Sarchie
407100787Sfenner/* Descriptor structure for each outgoing protocol we support */
408100787Sfennerstruct outproto {
409100787Sfenner	char	*name;		/* name of protocol */
410163387Sdwmalone	const char *key;	/* An ascii key for the bytes of the header */
411100787Sfenner	u_char	num;		/* IP protocol number */
412100787Sfenner	u_short	hdrlen;		/* max size of protocol header */
413100787Sfenner	u_short	port;		/* default base protocol-specific "port" */
414100787Sfenner	void	(*prepare)(struct outdata *);
415100787Sfenner				/* finish preparing an outgoing packet */
416100787Sfenner	int	(*check)(const u_char *, int);
417100787Sfenner				/* check an incoming packet */
418100787Sfenner};
419100787Sfenner
42046542Sarchie/* List of supported protocols. The first one is the default. The last
42146542Sarchie   one is the handler for generic protocols not explicitly listed. */
42246542Sarchiestruct	outproto protos[] = {
42346542Sarchie	{
42446542Sarchie		"udp",
425163387Sdwmalone		"spt dpt len sum",
42646542Sarchie		IPPROTO_UDP,
42746542Sarchie		sizeof(struct udphdr),
42846542Sarchie		32768 + 666,
42946542Sarchie		udp_prep,
43046542Sarchie		udp_check
43146542Sarchie	},
43246542Sarchie	{
43346542Sarchie		"tcp",
434163387Sdwmalone		"spt dpt seq     ack     xxflwin sum urp",
43546542Sarchie		IPPROTO_TCP,
43646542Sarchie		sizeof(struct tcphdr),
43746542Sarchie		32768 + 666,
43846542Sarchie		tcp_prep,
43946542Sarchie		tcp_check
44046542Sarchie	},
44146542Sarchie	{
44246542Sarchie		"gre",
443163387Sdwmalone		"flg pro len clid",
44446542Sarchie		IPPROTO_GRE,
44546542Sarchie		sizeof(struct grehdr),
44646542Sarchie		GRE_PPTP_PROTO,
44746542Sarchie		gre_prep,
44846542Sarchie		gre_check
44946542Sarchie	},
45046542Sarchie	{
451100535Sfenner		"icmp",
452163387Sdwmalone		"typ cod sum ",
453100535Sfenner		IPPROTO_ICMP,
454100535Sfenner		sizeof(struct icmp),
455100535Sfenner		0,
456100535Sfenner		icmp_prep,
457100535Sfenner		icmp_check
458100535Sfenner	},
459100535Sfenner	{
46046542Sarchie		NULL,
461163387Sdwmalone		NULL,
46246542Sarchie		0,
46346542Sarchie		2 * sizeof(u_short),
46446542Sarchie		0,
46546542Sarchie		gen_prep,
46646542Sarchie		gen_check
46746542Sarchie	},
46846542Sarchie};
46946542Sarchiestruct	outproto *proto = &protos[0];
47046542Sarchie
471163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id  off tlprsum srcip   dstip   opts";
472163387Sdwmalone
47318579Sfennerint
47418579Sfennermain(int argc, char **argv)
47518579Sfenner{
476100787Sfenner	register int op, code, n;
47718579Sfenner	register char *cp;
478100787Sfenner	register const char *err;
479100787Sfenner	register u_int32_t *ap;
480100787Sfenner	register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
48118579Sfenner	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
482100787Sfenner	register struct hostinfo *hi;
48318579Sfenner	int on = 1;
48418579Sfenner	register struct protoent *pe;
48518579Sfenner	register int ttl, probe, i;
48618579Sfenner	register int seq = 0;
487100787Sfenner	int tos = 0, settos = 0;
48818579Sfenner	register int lsrr = 0;
489100787Sfenner	register u_short off = 0;
490100787Sfenner	struct ifaddrlist *al;
491100787Sfenner	char errbuf[132];
49248221Sarchie	int requestPort = -1;
49318803Ssef	int sump = 0;
49418583Sfenner	int sockerrno;
49518579Sfenner
496100787Sfenner	/* Insure the socket fds won't be 0, 1 or 2 */
497100787Sfenner	if (open(devnull, O_RDONLY) < 0 ||
498100787Sfenner	    open(devnull, O_RDONLY) < 0 ||
499100787Sfenner	    open(devnull, O_RDONLY) < 0) {
500100787Sfenner		Fprintf(stderr, "%s: open \"%s\": %s\n",
501100787Sfenner		    prog, devnull, strerror(errno));
502100787Sfenner		exit(1);
503100787Sfenner	}
50418583Sfenner	/*
50518583Sfenner	 * Do the setuid-required stuff first, then lose priveleges ASAP.
50618583Sfenner	 * Do error checking for these two calls where they appeared in
50718583Sfenner	 * the original code.
50818583Sfenner	 */
50918583Sfenner	cp = "icmp";
51018583Sfenner	pe = getprotobyname(cp);
51118583Sfenner	if (pe) {
51218583Sfenner		if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
51318583Sfenner			sockerrno = errno;
51418583Sfenner		else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
51518583Sfenner			sockerrno = errno;
51618583Sfenner	}
51718583Sfenner
51818583Sfenner	setuid(getuid());
51918583Sfenner
52077816Sru#ifdef IPCTL_DEFTTL
52177816Sru	{
52277816Sru		int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
52377816Sru		size_t sz = sizeof(max_ttl);
52477816Sru
525100787Sfenner		if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
526100787Sfenner			perror("sysctl(net.inet.ip.ttl)");
527100787Sfenner			exit(1);
528100787Sfenner		}
52977816Sru	}
53077816Sru#else
53177816Sru	max_ttl = 30;
53277816Sru#endif
53377816Sru
534100787Sfenner	if (argv[0] == NULL)
535100787Sfenner		prog = "traceroute";
536100787Sfenner	else if ((cp = strrchr(argv[0], '/')) != NULL)
53718579Sfenner		prog = cp + 1;
53818579Sfenner	else
53918579Sfenner		prog = argv[0];
54018579Sfenner
54118579Sfenner	opterr = 0;
542176428Srpaulo	while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
54318579Sfenner		switch (op) {
544176428Srpaulo		case 'a':
545176428Srpaulo			as_path = 1;
546176428Srpaulo			break;
547176428Srpaulo
548176428Srpaulo		case 'A':
549176428Srpaulo			as_path = 1;
550176428Srpaulo			as_server = optarg;
551176428Srpaulo			break;
552176428Srpaulo
55318579Sfenner		case 'd':
55418579Sfenner			options |= SO_DEBUG;
55518579Sfenner			break;
55618579Sfenner
557163387Sdwmalone		case 'D':
558163387Sdwmalone			printdiff = 1;
559163387Sdwmalone			break;
560163387Sdwmalone
561158424Scjc		case 'e':
562158424Scjc			fixedPort = 1;
563158424Scjc			break;
564158424Scjc
565100787Sfenner		case 'f':
566100787Sfenner		case 'M':	/* FreeBSD compat. */
567100787Sfenner			first_ttl = str2val(optarg, "first ttl", 1, 255);
568100787Sfenner			break;
569100787Sfenner
570100787Sfenner		case 'F':
571100787Sfenner			off = IP_DF;
572100787Sfenner			break;
573100787Sfenner
57418579Sfenner		case 'g':
57518579Sfenner			if (lsrr >= NGATEWAYS) {
57618579Sfenner				Fprintf(stderr,
57718579Sfenner				    "%s: No more than %d gateways\n",
57818579Sfenner				    prog, NGATEWAYS);
57918579Sfenner				exit(1);
58018579Sfenner			}
581100787Sfenner			getaddr(gwlist + lsrr, optarg);
58218579Sfenner			++lsrr;
58318579Sfenner			break;
58418579Sfenner
585100787Sfenner		case 'i':
586100787Sfenner			device = optarg;
58747071Sarchie			break;
58847071Sarchie
589100787Sfenner		case 'I':
590100787Sfenner			proto = setproto("icmp");
591100787Sfenner			break;
592100787Sfenner
59318579Sfenner		case 'm':
594100787Sfenner			max_ttl = str2val(optarg, "max ttl", 1, 255);
59518579Sfenner			break;
59618579Sfenner
59718579Sfenner		case 'n':
59818579Sfenner			++nflag;
59918579Sfenner			break;
60018579Sfenner
60146542Sarchie		case 'P':
602100787Sfenner			proto = setproto(optarg);
60346542Sarchie			break;
60446542Sarchie
60518579Sfenner		case 'p':
606100787Sfenner			requestPort = (u_short)str2val(optarg, "port",
607100787Sfenner			    1, (1 << 16) - 1);
60818579Sfenner			break;
60918579Sfenner
61018579Sfenner		case 'q':
611100787Sfenner			nprobes = str2val(optarg, "nprobes", 1, -1);
61218579Sfenner			break;
61318579Sfenner
61418579Sfenner		case 'r':
61518579Sfenner			options |= SO_DONTROUTE;
61618579Sfenner			break;
61718579Sfenner
61818579Sfenner		case 's':
61918579Sfenner			/*
62018579Sfenner			 * set the ip source address of the outbound
62118579Sfenner			 * probe (e.g., on a multi-homed host).
62218579Sfenner			 */
62318579Sfenner			source = optarg;
62418579Sfenner			break;
62518579Sfenner
626100787Sfenner		case 'S':
627100787Sfenner			sump = 1;
628100787Sfenner			break;
629100787Sfenner
63018579Sfenner		case 't':
631100787Sfenner			tos = str2val(optarg, "tos", 0, 255);
632100787Sfenner			++settos;
63318579Sfenner			break;
63418579Sfenner
63518579Sfenner		case 'v':
63618579Sfenner			++verbose;
63718579Sfenner			break;
63818579Sfenner
639100787Sfenner		case 'x':
640100787Sfenner			doipcksum = (doipcksum == 0);
641100787Sfenner			break;
642100787Sfenner
64318579Sfenner		case 'w':
644100787Sfenner			waittime = str2val(optarg, "wait time",
645169144Smaxim			    1, 24 * 60 * 60);
64618579Sfenner			break;
64718579Sfenner
648100787Sfenner		case 'z':
649100787Sfenner			pausemsecs = str2val(optarg, "pause msecs",
650100787Sfenner			    0, 60 * 60 * 1000);
651100787Sfenner			break;
652100787Sfenner
65318579Sfenner		default:
65418579Sfenner			usage();
65518579Sfenner		}
65618579Sfenner
65748221Sarchie	/* Set requested port, if any, else default for this protocol */
65848221Sarchie	port = (requestPort != -1) ? requestPort : proto->port;
65948221Sarchie
660163387Sdwmalone	if (nprobes == -1)
661163387Sdwmalone		nprobes = printdiff ? 1 : 3;
662163387Sdwmalone
663100787Sfenner	if (first_ttl > max_ttl) {
664100787Sfenner		Fprintf(stderr,
665100787Sfenner		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
666100787Sfenner		    prog, first_ttl, max_ttl);
66747071Sarchie		exit(1);
66847071Sarchie	}
66947071Sarchie
670100787Sfenner	if (!doipcksum)
671100787Sfenner		Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
672100787Sfenner
673100787Sfenner	if (lsrr > 0)
674100787Sfenner		optlen = (lsrr + 1) * sizeof(gwlist[0]);
675100787Sfenner	minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
676100787Sfenner	packlen = minpacket;			/* minimum sized packet */
677100787Sfenner
67818579Sfenner	/* Process destination and optional packet size */
67918579Sfenner	switch (argc - optind) {
68018579Sfenner
68118579Sfenner	case 2:
682100787Sfenner		packlen = str2val(argv[optind + 1],
683100787Sfenner		    "packet length", minpacket, maxpacket);
684100787Sfenner		/* Fall through */
68518579Sfenner
68618579Sfenner	case 1:
687100787Sfenner		hostname = argv[optind];
688100787Sfenner		hi = gethostinfo(hostname);
689100787Sfenner		setsin(to, hi->addrs[0]);
690100787Sfenner		if (hi->n > 1)
691100787Sfenner			Fprintf(stderr,
692100787Sfenner		    "%s: Warning: %s has multiple addresses; using %s\n",
693100787Sfenner				prog, hostname, inet_ntoa(to->sin_addr));
694100787Sfenner		hostname = hi->name;
695100787Sfenner		hi->name = NULL;
696100787Sfenner		freehostinfo(hi);
69718579Sfenner		break;
69818579Sfenner
69918579Sfenner	default:
70018579Sfenner		usage();
70118579Sfenner	}
70218579Sfenner
70318579Sfenner#ifdef HAVE_SETLINEBUF
70418579Sfenner	setlinebuf (stdout);
70518579Sfenner#else
70618579Sfenner	setvbuf(stdout, NULL, _IOLBF, 0);
70718579Sfenner#endif
70818579Sfenner
70946542Sarchie	protlen = packlen - sizeof(*outip) - optlen;
71018579Sfenner
71118579Sfenner	outip = (struct ip *)malloc((unsigned)packlen);
71218579Sfenner	if (outip == NULL) {
71318579Sfenner		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
71418579Sfenner		exit(1);
71518579Sfenner	}
71618579Sfenner	memset((char *)outip, 0, packlen);
71718579Sfenner
71818579Sfenner	outip->ip_v = IPVERSION;
719100787Sfenner	if (settos)
720100787Sfenner		outip->ip_tos = tos;
721100787Sfenner#ifdef BYTESWAP_IP_HDR
72218579Sfenner	outip->ip_len = htons(packlen);
723100787Sfenner	outip->ip_off = htons(off);
72418579Sfenner#else
72518579Sfenner	outip->ip_len = packlen;
726100787Sfenner	outip->ip_off = off;
72718579Sfenner#endif
72846542Sarchie	outip->ip_p = proto->num;
729100787Sfenner	outp = (u_char *)(outip + 1);
73018579Sfenner#ifdef HAVE_RAW_OPTIONS
73118579Sfenner	if (lsrr > 0) {
73218579Sfenner		register u_char *optlist;
73318579Sfenner
734100787Sfenner		optlist = outp;
735100787Sfenner		outp += optlen;
73618579Sfenner
73718579Sfenner		/* final hop */
73818579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
73918579Sfenner
74018579Sfenner		outip->ip_dst.s_addr = gwlist[0];
74118579Sfenner
74218579Sfenner		/* force 4 byte alignment */
74318579Sfenner		optlist[0] = IPOPT_NOP;
74418579Sfenner		/* loose source route option */
74518579Sfenner		optlist[1] = IPOPT_LSRR;
74618579Sfenner		i = lsrr * sizeof(gwlist[0]);
74718579Sfenner		optlist[2] = i + 3;
74818579Sfenner		/* Pointer to LSRR addresses */
74918579Sfenner		optlist[3] = IPOPT_MINOFF;
75018579Sfenner		memcpy(optlist + 4, gwlist + 1, i);
75118579Sfenner	} else
75218579Sfenner#endif
75318579Sfenner		outip->ip_dst = to->sin_addr;
75418579Sfenner
755100787Sfenner	outip->ip_hl = (outp - (u_char *)outip) >> 2;
75618579Sfenner	ident = (getpid() & 0xffff) | 0x8000;
75718579Sfenner
75818583Sfenner	if (pe == NULL) {
75918579Sfenner		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
76018579Sfenner		exit(1);
76118579Sfenner	}
76218583Sfenner	if (s < 0) {
76318583Sfenner		errno = sockerrno;
76418579Sfenner		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
76518579Sfenner		exit(1);
76618579Sfenner	}
76718579Sfenner	if (options & SO_DEBUG)
76818579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
76918579Sfenner		    sizeof(on));
77018579Sfenner	if (options & SO_DONTROUTE)
77118579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
77218579Sfenner		    sizeof(on));
77318579Sfenner
77458804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
77558804Sshin	if (setpolicy(s, "in bypass") < 0)
77666809Skris		errx(1, "%s", ipsec_strerror());
77758804Sshin
77858804Sshin	if (setpolicy(s, "out bypass") < 0)
77966809Skris		errx(1, "%s", ipsec_strerror());
78058804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
78158804Sshin
78218583Sfenner	if (sndsock < 0) {
78318583Sfenner		errno = sockerrno;
78418579Sfenner		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
78518579Sfenner		exit(1);
78618579Sfenner	}
78718579Sfenner
78818579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
78918579Sfenner	if (lsrr > 0) {
79018579Sfenner		u_char optlist[MAX_IPOPTLEN];
79118579Sfenner
79218579Sfenner		cp = "ip";
79318579Sfenner		if ((pe = getprotobyname(cp)) == NULL) {
79418579Sfenner			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
79518579Sfenner			exit(1);
79618579Sfenner		}
79718579Sfenner
79818579Sfenner		/* final hop */
79918579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
80018579Sfenner		++lsrr;
80118579Sfenner
80218579Sfenner		/* force 4 byte alignment */
80318579Sfenner		optlist[0] = IPOPT_NOP;
80418579Sfenner		/* loose source route option */
80518579Sfenner		optlist[1] = IPOPT_LSRR;
80618579Sfenner		i = lsrr * sizeof(gwlist[0]);
80718579Sfenner		optlist[2] = i + 3;
80818579Sfenner		/* Pointer to LSRR addresses */
80918579Sfenner		optlist[3] = IPOPT_MINOFF;
81018579Sfenner		memcpy(optlist + 4, gwlist, i);
81118579Sfenner
812100787Sfenner		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
813100787Sfenner		    (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
81418579Sfenner			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
81518579Sfenner			    prog, strerror(errno));
81618579Sfenner			exit(1);
81718579Sfenner		    }
81818579Sfenner	}
81918579Sfenner#endif
82018579Sfenner
82118579Sfenner#ifdef SO_SNDBUF
82218579Sfenner	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
82318579Sfenner	    sizeof(packlen)) < 0) {
82418579Sfenner		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
82518579Sfenner		exit(1);
82618579Sfenner	}
82718579Sfenner#endif
82818579Sfenner#ifdef IP_HDRINCL
82918579Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
83018579Sfenner	    sizeof(on)) < 0) {
83118579Sfenner		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
83218579Sfenner		exit(1);
83318579Sfenner	}
834100787Sfenner#else
835100787Sfenner#ifdef IP_TOS
836100787Sfenner	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
837100787Sfenner	    (char *)&tos, sizeof(tos)) < 0) {
838100787Sfenner		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
839100787Sfenner		    prog, tos, strerror(errno));
840100787Sfenner		exit(1);
841100787Sfenner	}
84218579Sfenner#endif
843100787Sfenner#endif
84418579Sfenner	if (options & SO_DEBUG)
84518579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
84618579Sfenner		    sizeof(on));
84718579Sfenner	if (options & SO_DONTROUTE)
84818579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
84918579Sfenner		    sizeof(on));
85018579Sfenner
851100787Sfenner	/* Get the interface address list */
852100787Sfenner	n = ifaddrlist(&al, errbuf);
853100787Sfenner	if (n < 0) {
854100787Sfenner		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
855100787Sfenner		exit(1);
856100787Sfenner	}
857100787Sfenner	if (n == 0) {
858100787Sfenner		Fprintf(stderr,
859100787Sfenner		    "%s: Can't find any network interfaces\n", prog);
860100787Sfenner		exit(1);
861100787Sfenner	}
862100787Sfenner
863100787Sfenner	/* Look for a specific device */
864100787Sfenner	if (device != NULL) {
865100787Sfenner		for (i = n; i > 0; --i, ++al)
866100787Sfenner			if (strcmp(device, al->device) == 0)
867100787Sfenner				break;
868100787Sfenner		if (i <= 0) {
869100787Sfenner			Fprintf(stderr, "%s: Can't find interface %.32s\n",
870100787Sfenner			    prog, device);
871100787Sfenner			exit(1);
87218579Sfenner		}
87318579Sfenner	}
87418579Sfenner
875100787Sfenner	/* Determine our source address */
876100787Sfenner	if (source == NULL) {
877100787Sfenner		/*
878100787Sfenner		 * If a device was specified, use the interface address.
879100787Sfenner		 * Otherwise, try to determine our source address.
880100787Sfenner		 */
881100787Sfenner		if (device != NULL)
882100787Sfenner			setsin(from, al->addr);
883100787Sfenner		else if ((err = findsaddr(to, from)) != NULL) {
884100787Sfenner			Fprintf(stderr, "%s: findsaddr: %s\n",
885100787Sfenner			    prog, err);
886100787Sfenner			exit(1);
887100787Sfenner		}
888100787Sfenner	} else {
889100787Sfenner		hi = gethostinfo(source);
890100787Sfenner		source = hi->name;
891100787Sfenner		hi->name = NULL;
892100787Sfenner		/*
893100787Sfenner		 * If the device was specified make sure it
894100787Sfenner		 * corresponds to the source address specified.
895100787Sfenner		 * Otherwise, use the first address (and warn if
896100787Sfenner		 * there are more than one).
897100787Sfenner		 */
898100787Sfenner		if (device != NULL) {
899100787Sfenner			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
900100787Sfenner				if (*ap == al->addr)
901100787Sfenner					break;
902100787Sfenner			if (i <= 0) {
903100787Sfenner				Fprintf(stderr,
904100787Sfenner				    "%s: %s is not on interface %.32s\n",
905100787Sfenner				    prog, source, device);
906100787Sfenner				exit(1);
907100787Sfenner			}
908100787Sfenner			setsin(from, *ap);
909100787Sfenner		} else {
910100787Sfenner			setsin(from, hi->addrs[0]);
911100787Sfenner			if (hi->n > 1)
912100787Sfenner				Fprintf(stderr,
913100787Sfenner			"%s: Warning: %s has multiple addresses; using %s\n",
914100787Sfenner				    prog, source, inet_ntoa(from->sin_addr));
915100787Sfenner		}
916100787Sfenner		freehostinfo(hi);
917100787Sfenner	}
918100787Sfenner
919100787Sfenner	outip->ip_src = from->sin_addr;
920128365Spb
921128365Spb	/* Check the source address (-s), if any, is valid */
922100787Sfenner	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
923100787Sfenner		Fprintf(stderr, "%s: bind: %s\n",
924100787Sfenner		    prog, strerror(errno));
925100787Sfenner		exit (1);
926100787Sfenner	}
927100787Sfenner
928176428Srpaulo	if (as_path) {
929176428Srpaulo		asn = as_setup(as_server);
930176428Srpaulo		if (asn == NULL) {
931176428Srpaulo			Fprintf(stderr, "%s: as_setup failed, AS# lookups"
932176428Srpaulo			    " disabled\n", prog);
933176428Srpaulo			(void)fflush(stderr);
934176428Srpaulo			as_path = 0;
935176428Srpaulo		}
936176428Srpaulo	}
937176428Srpaulo
93858804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
93958804Sshin	if (setpolicy(sndsock, "in bypass") < 0)
94066809Skris		errx(1, "%s", ipsec_strerror());
94158804Sshin
94258804Sshin	if (setpolicy(sndsock, "out bypass") < 0)
94366809Skris		errx(1, "%s", ipsec_strerror());
94458804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
94558804Sshin
94618579Sfenner	Fprintf(stderr, "%s to %s (%s)",
94718579Sfenner	    prog, hostname, inet_ntoa(to->sin_addr));
94818579Sfenner	if (source)
94918579Sfenner		Fprintf(stderr, " from %s", source);
95018579Sfenner	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
95118579Sfenner	(void)fflush(stderr);
95218579Sfenner
953100787Sfenner	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
95418579Sfenner		u_int32_t lastaddr = 0;
955100787Sfenner		int gotlastaddr = 0;
95618579Sfenner		int got_there = 0;
95718579Sfenner		int unreachable = 0;
958100787Sfenner		int sentfirst = 0;
95918695Ssef		int loss;
96018579Sfenner
96118579Sfenner		Printf("%2d ", ttl);
96218695Ssef		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
96318579Sfenner			register int cc;
96418579Sfenner			struct timeval t1, t2;
96518579Sfenner			struct timezone tz;
96618579Sfenner			register struct ip *ip;
96746542Sarchie			struct outdata outdata;
96818579Sfenner
969100787Sfenner			if (sentfirst && pausemsecs > 0)
970100787Sfenner				usleep(pausemsecs * 1000);
97146542Sarchie			/* Prepare outgoing data */
97246542Sarchie			outdata.seq = ++seq;
97346542Sarchie			outdata.ttl = ttl;
97446542Sarchie
97546542Sarchie			/* Avoid alignment problems by copying bytewise: */
97618579Sfenner			(void)gettimeofday(&t1, &tz);
97746542Sarchie			memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
97846542Sarchie
97946542Sarchie			/* Finalize and send packet */
98046542Sarchie			(*proto->prepare)(&outdata);
98146542Sarchie			send_probe(seq, ttl);
982100787Sfenner			++sentfirst;
98346542Sarchie
98446542Sarchie			/* Wait for a reply */
985100787Sfenner			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
98618583Sfenner				double T;
98718583Sfenner				int precis;
98818583Sfenner
98918579Sfenner				(void)gettimeofday(&t2, &tz);
990100787Sfenner				i = packet_ok(packet, cc, from, seq);
99118579Sfenner				/* Skip short packet */
99218579Sfenner				if (i == 0)
99318579Sfenner					continue;
994100787Sfenner				if (!gotlastaddr ||
995100787Sfenner				    from->sin_addr.s_addr != lastaddr) {
996154192Spav					if (gotlastaddr) printf("\n   ");
997100787Sfenner					print(packet, cc, from);
998100787Sfenner					lastaddr = from->sin_addr.s_addr;
999100787Sfenner					++gotlastaddr;
100018579Sfenner				}
100118583Sfenner				T = deltaT(&t1, &t2);
100218583Sfenner#ifdef SANE_PRECISION
100318583Sfenner				if (T >= 1000.0)
100418583Sfenner					precis = 0;
100518583Sfenner				else if (T >= 100.0)
100618583Sfenner					precis = 1;
100718583Sfenner				else if (T >= 10.0)
100818583Sfenner					precis = 2;
100918583Sfenner				else
101018583Sfenner#endif
101118583Sfenner					precis = 3;
101218583Sfenner				Printf("  %.*f ms", precis, T);
1013163387Sdwmalone				if (printdiff) {
1014163387Sdwmalone					Printf("\n");
1015163387Sdwmalone					Printf("%*.*s%s\n",
1016163387Sdwmalone					    -(outip->ip_hl << 3),
1017163387Sdwmalone					    outip->ip_hl << 3,
1018163387Sdwmalone					    ip_hdr_key,
1019163387Sdwmalone					    proto->key);
1020163387Sdwmalone					pkt_compare((void *)outip, packlen,
1021163387Sdwmalone					    (void *)hip, hiplen);
1022163387Sdwmalone				}
1023100535Sfenner				if (i == -2) {
1024100567Sdcs#ifndef ARCHAIC
1025100535Sfenner					ip = (struct ip *)packet;
1026100535Sfenner					if (ip->ip_ttl <= 1)
1027100535Sfenner						Printf(" !");
1028100535Sfenner#endif
1029100535Sfenner					++got_there;
1030100535Sfenner					break;
1031100535Sfenner				}
103218579Sfenner				/* time exceeded in transit */
103318579Sfenner				if (i == -1)
103418579Sfenner					break;
103518579Sfenner				code = i - 1;
103618579Sfenner				switch (code) {
103718579Sfenner
103818579Sfenner				case ICMP_UNREACH_PORT:
103918579Sfenner#ifndef ARCHAIC
104018579Sfenner					ip = (struct ip *)packet;
104118579Sfenner					if (ip->ip_ttl <= 1)
104218579Sfenner						Printf(" !");
104318579Sfenner#endif
104418579Sfenner					++got_there;
104518579Sfenner					break;
104618579Sfenner
104718579Sfenner				case ICMP_UNREACH_NET:
104818579Sfenner					++unreachable;
104918579Sfenner					Printf(" !N");
105018579Sfenner					break;
105118579Sfenner
105218579Sfenner				case ICMP_UNREACH_HOST:
105318579Sfenner					++unreachable;
105418579Sfenner					Printf(" !H");
105518579Sfenner					break;
105618579Sfenner
105718579Sfenner				case ICMP_UNREACH_PROTOCOL:
105818579Sfenner					++got_there;
105918579Sfenner					Printf(" !P");
106018579Sfenner					break;
106118579Sfenner
106218579Sfenner				case ICMP_UNREACH_NEEDFRAG:
106318579Sfenner					++unreachable;
1064100787Sfenner					Printf(" !F-%d", pmtu);
106518579Sfenner					break;
106618579Sfenner
106718579Sfenner				case ICMP_UNREACH_SRCFAIL:
106818579Sfenner					++unreachable;
106918579Sfenner					Printf(" !S");
107018579Sfenner					break;
107118579Sfenner
1072159576Sdwmalone				case ICMP_UNREACH_NET_UNKNOWN:
1073159576Sdwmalone					++unreachable;
1074159576Sdwmalone					Printf(" !U");
1075159576Sdwmalone					break;
1076159576Sdwmalone
1077159576Sdwmalone				case ICMP_UNREACH_HOST_UNKNOWN:
1078159576Sdwmalone					++unreachable;
1079159576Sdwmalone					Printf(" !W");
1080159576Sdwmalone					break;
1081159576Sdwmalone
1082159576Sdwmalone				case ICMP_UNREACH_ISOLATED:
1083159576Sdwmalone					++unreachable;
1084159576Sdwmalone					Printf(" !I");
1085159576Sdwmalone					break;
1086159576Sdwmalone
1087159576Sdwmalone				case ICMP_UNREACH_NET_PROHIB:
1088159576Sdwmalone					++unreachable;
1089159576Sdwmalone					Printf(" !A");
1090159576Sdwmalone					break;
1091159576Sdwmalone
1092159576Sdwmalone				case ICMP_UNREACH_HOST_PROHIB:
1093159576Sdwmalone					++unreachable;
1094159576Sdwmalone					Printf(" !Z");
1095159576Sdwmalone					break;
1096159576Sdwmalone
1097159576Sdwmalone				case ICMP_UNREACH_TOSNET:
1098159576Sdwmalone					++unreachable;
1099159576Sdwmalone					Printf(" !Q");
1100159576Sdwmalone					break;
1101159576Sdwmalone
1102159576Sdwmalone				case ICMP_UNREACH_TOSHOST:
1103159576Sdwmalone					++unreachable;
1104159576Sdwmalone					Printf(" !T");
1105159576Sdwmalone					break;
1106159576Sdwmalone
110718579Sfenner				case ICMP_UNREACH_FILTER_PROHIB:
110818579Sfenner					++unreachable;
110918579Sfenner					Printf(" !X");
111018579Sfenner					break;
111118579Sfenner
1112100787Sfenner				case ICMP_UNREACH_HOST_PRECEDENCE:
1113100787Sfenner					++unreachable;
1114100787Sfenner					Printf(" !V");
1115100787Sfenner					break;
1116100787Sfenner
1117100787Sfenner				case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1118100787Sfenner					++unreachable;
1119100787Sfenner					Printf(" !C");
1120100787Sfenner					break;
1121100787Sfenner
112218579Sfenner				default:
112318579Sfenner					++unreachable;
112418579Sfenner					Printf(" !<%d>", code);
112518579Sfenner					break;
112618579Sfenner				}
112718579Sfenner				break;
112818579Sfenner			}
112918695Ssef			if (cc == 0) {
113018695Ssef				loss++;
113118579Sfenner				Printf(" *");
113218695Ssef			}
113318579Sfenner			(void)fflush(stdout);
113418579Sfenner		}
113518803Ssef		if (sump) {
113618811Ssef			Printf(" (%d%% loss)", (loss * 100) / nprobes);
113718803Ssef		}
113818579Sfenner		putchar('\n');
113918579Sfenner		if (got_there ||
114018579Sfenner		    (unreachable > 0 && unreachable >= nprobes - 1))
114118579Sfenner			break;
114218579Sfenner	}
1143176428Srpaulo	if (as_path)
1144176428Srpaulo		as_shutdown(asn);
114518579Sfenner	exit(0);
114618579Sfenner}
114718579Sfenner
114818579Sfennerint
114918579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp,
1150100787Sfenner    register const struct timeval *tp)
115118579Sfenner{
115266810Skris	fd_set *fdsp;
115366810Skris	size_t nfds;
115418579Sfenner	struct timeval now, wait;
115518579Sfenner	struct timezone tz;
115618579Sfenner	register int cc = 0;
115744086Sdes	register int error;
115818579Sfenner	int fromlen = sizeof(*fromp);
115918579Sfenner
116066810Skris	nfds = howmany(sock + 1, NFDBITS);
116198709Srobert	if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
116266810Skris		err(1, "malloc");
116398709Srobert	memset(fdsp, 0, nfds * sizeof(fd_mask));
116466810Skris	FD_SET(sock, fdsp);
116518579Sfenner
116618579Sfenner	wait.tv_sec = tp->tv_sec + waittime;
116718579Sfenner	wait.tv_usec = tp->tv_usec;
116818579Sfenner	(void)gettimeofday(&now, &tz);
116918579Sfenner	tvsub(&wait, &now);
117044086Sdes	if (wait.tv_sec < 0) {
117144086Sdes		wait.tv_sec = 0;
117244086Sdes		wait.tv_usec = 1;
117344086Sdes	}
117418579Sfenner
117566810Skris	error = select(sock + 1, fdsp, NULL, NULL, &wait);
117644086Sdes	if (error == -1 && errno == EINVAL) {
117744086Sdes		Fprintf(stderr, "%s: botched select() args\n", prog);
117844086Sdes		exit(1);
117944086Sdes	}
118044086Sdes	if (error > 0)
1181100787Sfenner		cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
118218579Sfenner			    (struct sockaddr *)fromp, &fromlen);
118318579Sfenner
118466810Skris	free(fdsp);
118518579Sfenner	return(cc);
118618579Sfenner}
118718579Sfenner
1188100787Sfennervoid
1189100787Sfennersend_probe(int seq, int ttl)
1190100787Sfenner{
1191100787Sfenner	register int cc;
1192100787Sfenner
1193100787Sfenner	outip->ip_ttl = ttl;
1194100787Sfenner	outip->ip_id = htons(ident + seq);
1195100787Sfenner
1196100787Sfenner	/* XXX undocumented debugging hack */
1197100787Sfenner	if (verbose > 1) {
1198100787Sfenner		register const u_short *sp;
1199100787Sfenner		register int nshorts, i;
1200100787Sfenner
1201100787Sfenner		sp = (u_short *)outip;
1202100787Sfenner		nshorts = (u_int)packlen / sizeof(u_short);
1203100787Sfenner		i = 0;
1204100787Sfenner		Printf("[ %d bytes", packlen);
1205100787Sfenner		while (--nshorts >= 0) {
1206100787Sfenner			if ((i++ % 8) == 0)
1207100787Sfenner				Printf("\n\t");
1208100787Sfenner			Printf(" %04x", ntohs(*sp++));
1209100787Sfenner		}
1210100787Sfenner		if (packlen & 1) {
1211100787Sfenner			if ((i % 8) == 0)
1212100787Sfenner				Printf("\n\t");
1213100787Sfenner			Printf(" %02x", *(u_char *)sp);
1214100787Sfenner		}
1215100787Sfenner		Printf("]\n");
1216100787Sfenner	}
1217100787Sfenner
1218100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL)
1219100787Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1220100787Sfenner	    (char *)&ttl, sizeof(ttl)) < 0) {
1221100787Sfenner		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1222100787Sfenner		    prog, ttl, strerror(errno));
1223100787Sfenner		exit(1);
1224100787Sfenner	}
1225100787Sfenner#endif
1226100787Sfenner
1227100787Sfenner	cc = sendto(sndsock, (char *)outip,
1228100787Sfenner	    packlen, 0, &whereto, sizeof(whereto));
1229100787Sfenner	if (cc < 0 || cc != packlen)  {
1230100787Sfenner		if (cc < 0)
1231100787Sfenner			Fprintf(stderr, "%s: sendto: %s\n",
1232100787Sfenner			    prog, strerror(errno));
1233100787Sfenner		Printf("%s: wrote %s %d chars, ret=%d\n",
1234100787Sfenner		    prog, hostname, packlen, cc);
1235100787Sfenner		(void)fflush(stdout);
1236100787Sfenner	}
1237100787Sfenner}
1238100787Sfenner
123958804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
124058804Sshinint
124158804Sshinsetpolicy(so, policy)
124258804Sshin	int so;
124358804Sshin	char *policy;
124458804Sshin{
124558804Sshin	char *buf;
124658804Sshin
124758804Sshin	buf = ipsec_set_policy(policy, strlen(policy));
124858804Sshin	if (buf == NULL) {
124966809Skris		warnx("%s", ipsec_strerror());
125058804Sshin		return -1;
125158804Sshin	}
125258804Sshin	(void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
125358804Sshin		buf, ipsec_get_policylen(buf));
125458804Sshin
125558804Sshin	free(buf);
125658804Sshin
125758804Sshin	return 0;
125858804Sshin}
125958804Sshin#endif
126058804Sshin
126118579Sfennerdouble
126218579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p)
126318579Sfenner{
126418579Sfenner	register double dt;
126518579Sfenner
126618579Sfenner	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
126718579Sfenner	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
126818579Sfenner	return (dt);
126918579Sfenner}
127018579Sfenner
127118579Sfenner/*
127218579Sfenner * Convert an ICMP "type" field to a printable string.
127318579Sfenner */
127418579Sfennerchar *
127518579Sfennerpr_type(register u_char t)
127618579Sfenner{
127718579Sfenner	static char *ttab[] = {
127818579Sfenner	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
127918579Sfenner	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
128018579Sfenner	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
128118579Sfenner	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
128218579Sfenner	"Info Reply"
128318579Sfenner	};
128418579Sfenner
128518579Sfenner	if (t > 16)
128618579Sfenner		return("OUT-OF-RANGE");
128718579Sfenner
128818579Sfenner	return(ttab[t]);
128918579Sfenner}
129018579Sfenner
129118579Sfennerint
129218579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
129318579Sfenner    register int seq)
129418579Sfenner{
129518579Sfenner	register struct icmp *icp;
129618579Sfenner	register u_char type, code;
129718579Sfenner	register int hlen;
129818579Sfenner#ifndef ARCHAIC
129918579Sfenner	register struct ip *ip;
130018579Sfenner
130118579Sfenner	ip = (struct ip *) buf;
130218579Sfenner	hlen = ip->ip_hl << 2;
130318579Sfenner	if (cc < hlen + ICMP_MINLEN) {
130418579Sfenner		if (verbose)
130518579Sfenner			Printf("packet too short (%d bytes) from %s\n", cc,
130618579Sfenner				inet_ntoa(from->sin_addr));
130718579Sfenner		return (0);
130818579Sfenner	}
130918579Sfenner	cc -= hlen;
131018579Sfenner	icp = (struct icmp *)(buf + hlen);
131118579Sfenner#else
131218579Sfenner	icp = (struct icmp *)buf;
131318579Sfenner#endif
131418579Sfenner	type = icp->icmp_type;
131518579Sfenner	code = icp->icmp_code;
1316100787Sfenner	/* Path MTU Discovery (RFC1191) */
1317100787Sfenner	if (code != ICMP_UNREACH_NEEDFRAG)
1318100787Sfenner		pmtu = 0;
1319100787Sfenner	else {
1320100787Sfenner#ifdef HAVE_ICMP_NEXTMTU
1321100787Sfenner		pmtu = ntohs(icp->icmp_nextmtu);
1322100787Sfenner#else
1323100787Sfenner		pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1324100787Sfenner#endif
1325100787Sfenner	}
1326100535Sfenner	if (type == ICMP_ECHOREPLY
1327100535Sfenner	    && proto->num == IPPROTO_ICMP
1328124859Scperciva	    && (*proto->check)((u_char *)icp, (u_char)seq))
1329100535Sfenner		return -2;
133018579Sfenner	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
133118579Sfenner	    type == ICMP_UNREACH) {
133246542Sarchie		u_char *inner;
133318579Sfenner
133418579Sfenner		hip = &icp->icmp_ip;
1335163387Sdwmalone		hiplen = ((u_char *)icp + cc) - (u_char *)hip;
133618579Sfenner		hlen = hip->ip_hl << 2;
133746542Sarchie		inner = (u_char *)((u_char *)hip + hlen);
133846542Sarchie		if (hlen + 12 <= cc
133946542Sarchie		    && hip->ip_p == proto->num
1340124859Scperciva		    && (*proto->check)(inner, (u_char)seq))
134118579Sfenner			return (type == ICMP_TIMXCEED ? -1 : code + 1);
134218579Sfenner	}
134318579Sfenner#ifndef ARCHAIC
134418579Sfenner	if (verbose) {
134518579Sfenner		register int i;
134618579Sfenner		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
134718579Sfenner
134818579Sfenner		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
134918579Sfenner		Printf("%s: icmp type %d (%s) code %d\n",
135018579Sfenner		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
135118579Sfenner		for (i = 4; i < cc ; i += sizeof(*lp))
135218579Sfenner			Printf("%2d: x%8.8x\n", i, *lp++);
135318579Sfenner	}
135418579Sfenner#endif
135518579Sfenner	return(0);
135618579Sfenner}
135718579Sfenner
135846542Sarchievoid
1359100535Sfennericmp_prep(struct outdata *outdata)
1360100535Sfenner{
1361100787Sfenner	struct icmp *const icmpheader = (struct icmp *) outp;
1362100535Sfenner
1363100535Sfenner	icmpheader->icmp_type = ICMP_ECHO;
1364100535Sfenner	icmpheader->icmp_id = htons(ident);
1365100535Sfenner	icmpheader->icmp_seq = htons(outdata->seq);
1366100535Sfenner	icmpheader->icmp_cksum = 0;
1367100789Sfenner	icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
1368100535Sfenner	if (icmpheader->icmp_cksum == 0)
1369100535Sfenner		icmpheader->icmp_cksum = 0xffff;
1370100535Sfenner}
1371100535Sfenner
1372100535Sfennerint
1373100535Sfennericmp_check(const u_char *data, int seq)
1374100535Sfenner{
1375100535Sfenner	struct icmp *const icmpheader = (struct icmp *) data;
1376100535Sfenner
1377100535Sfenner	return (icmpheader->icmp_id == htons(ident)
1378100535Sfenner	    && icmpheader->icmp_seq == htons(seq));
1379100535Sfenner}
1380100535Sfenner
1381100535Sfennervoid
138246542Sarchieudp_prep(struct outdata *outdata)
138346542Sarchie{
1384100787Sfenner	struct udphdr *const outudp = (struct udphdr *) outp;
138518579Sfenner
1386158424Scjc	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1387158424Scjc	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1388100787Sfenner	outudp->uh_ulen = htons((u_short)protlen);
1389100789Sfenner	outudp->uh_sum = 0;
1390100787Sfenner	if (doipcksum) {
1391100789Sfenner	    u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
1392100789Sfenner	    outudp->uh_sum = (sum) ? sum : 0xffff;
1393100787Sfenner	}
1394100789Sfenner
1395100789Sfenner	return;
139646542Sarchie}
139746542Sarchie
139846542Sarchieint
139946542Sarchieudp_check(const u_char *data, int seq)
140046542Sarchie{
140146542Sarchie	struct udphdr *const udp = (struct udphdr *) data;
140246542Sarchie
1403158424Scjc	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1404158424Scjc	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
140546542Sarchie}
140646542Sarchie
140718579Sfennervoid
140846542Sarchietcp_prep(struct outdata *outdata)
140946542Sarchie{
1410100787Sfenner	struct tcphdr *const tcp = (struct tcphdr *) outp;
141146542Sarchie
141246542Sarchie	tcp->th_sport = htons(ident);
1413158424Scjc	tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1414158424Scjc	tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
1415158424Scjc	    (fixedPort ? outdata->seq : 0));
141646542Sarchie	tcp->th_ack = 0;
141746542Sarchie	tcp->th_off = 5;
141846542Sarchie	tcp->th_flags = TH_SYN;
1419100789Sfenner	tcp->th_sum = 0;
1420100789Sfenner
1421100789Sfenner	if (doipcksum) {
1422100789Sfenner	    u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
1423100789Sfenner	    tcp->th_sum = (sum) ? sum : 0xffff;
1424100789Sfenner	}
142546542Sarchie}
142646542Sarchie
142746542Sarchieint
142846542Sarchietcp_check(const u_char *data, int seq)
142946542Sarchie{
143046542Sarchie	struct tcphdr *const tcp = (struct tcphdr *) data;
143146542Sarchie
143246542Sarchie	return (ntohs(tcp->th_sport) == ident
1433158424Scjc	    && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
1434158424Scjc	    && tcp->th_seq == (ident << 16) | (port + seq);
143546542Sarchie}
143646542Sarchie
143746542Sarchievoid
143846542Sarchiegre_prep(struct outdata *outdata)
143946542Sarchie{
1440100787Sfenner	struct grehdr *const gre = (struct grehdr *) outp;
144146542Sarchie
144246542Sarchie	gre->flags = htons(0x2001);
144346542Sarchie	gre->proto = htons(port);
144446542Sarchie	gre->length = 0;
144546542Sarchie	gre->callId = htons(ident + outdata->seq);
144646542Sarchie}
144746542Sarchie
144846542Sarchieint
144946542Sarchiegre_check(const u_char *data, int seq)
145046542Sarchie{
145146542Sarchie	struct grehdr *const gre = (struct grehdr *) data;
145246542Sarchie
145346542Sarchie	return(ntohs(gre->proto) == port
145446542Sarchie	    && ntohs(gre->callId) == ident + seq);
145546542Sarchie}
145646542Sarchie
145746542Sarchievoid
145846542Sarchiegen_prep(struct outdata *outdata)
145946542Sarchie{
1460100787Sfenner	u_int16_t *const ptr = (u_int16_t *) outp;
146146542Sarchie
146246542Sarchie	ptr[0] = htons(ident);
146346542Sarchie	ptr[1] = htons(port + outdata->seq);
146446542Sarchie}
146546542Sarchie
146646542Sarchieint
146746542Sarchiegen_check(const u_char *data, int seq)
146846542Sarchie{
146946542Sarchie	u_int16_t *const ptr = (u_int16_t *) data;
147046542Sarchie
147146542Sarchie	return(ntohs(ptr[0]) == ident
147246542Sarchie	    && ntohs(ptr[1]) == port + seq);
147346542Sarchie}
147446542Sarchie
147546542Sarchievoid
147618579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from)
147718579Sfenner{
147818579Sfenner	register struct ip *ip;
147918579Sfenner	register int hlen;
148018579Sfenner
148118579Sfenner	ip = (struct ip *) buf;
148218579Sfenner	hlen = ip->ip_hl << 2;
148318579Sfenner	cc -= hlen;
148418579Sfenner
1485176428Srpaulo	if (as_path)
1486176428Srpaulo		Printf(" [AS%d]", as_lookup(asn, &from->sin_addr));
1487176428Srpaulo
148818579Sfenner	if (nflag)
148918579Sfenner		Printf(" %s", inet_ntoa(from->sin_addr));
149018579Sfenner	else
149118579Sfenner		Printf(" %s (%s)", inetname(from->sin_addr),
149218579Sfenner		    inet_ntoa(from->sin_addr));
149318579Sfenner
149418579Sfenner	if (verbose)
149518579Sfenner		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
149618579Sfenner}
149718579Sfenner
149818579Sfenner/*
1499100789Sfenner * Checksum routine for UDP and TCP headers.
1500100789Sfenner */
1501100789Sfenneru_short
1502100789Sfennerp_cksum(struct ip *ip, u_short *data, int len)
1503100789Sfenner{
1504100789Sfenner	static struct ipovly ipo;
1505100789Sfenner	u_short sumh, sumd;
1506100789Sfenner	u_long sumt;
1507100789Sfenner
1508100789Sfenner	ipo.ih_pr = ip->ip_p;
1509100789Sfenner	ipo.ih_len = htons(len);
1510100789Sfenner	ipo.ih_src = ip->ip_src;
1511100789Sfenner	ipo.ih_dst = ip->ip_dst;
1512100789Sfenner
1513100789Sfenner	sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
1514100789Sfenner	sumd = in_cksum((u_short*)data, len);	      /* payload data cksum */
1515100789Sfenner	sumt = (sumh << 16) | (sumd);
1516100789Sfenner
1517100789Sfenner	return ~in_cksum((u_short*)&sumt, sizeof(sumt));
1518100789Sfenner}
1519100789Sfenner
1520100789Sfenner/*
152118579Sfenner * Checksum routine for Internet Protocol family headers (C Version)
152218579Sfenner */
1523100535Sfenneru_short
152418579Sfennerin_cksum(register u_short *addr, register int len)
152518579Sfenner{
152618579Sfenner	register int nleft = len;
152718579Sfenner	register u_short *w = addr;
152818579Sfenner	register u_short answer;
152918579Sfenner	register int sum = 0;
153018579Sfenner
153118579Sfenner	/*
153218579Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
153318579Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
153418579Sfenner	 *  back all the carry bits from the top 16 bits into the lower
153518579Sfenner	 *  16 bits.
153618579Sfenner	 */
153718579Sfenner	while (nleft > 1)  {
153818579Sfenner		sum += *w++;
153918579Sfenner		nleft -= 2;
154018579Sfenner	}
154118579Sfenner
154218579Sfenner	/* mop up an odd byte, if necessary */
154318579Sfenner	if (nleft == 1)
154418579Sfenner		sum += *(u_char *)w;
154518579Sfenner
154618579Sfenner	/*
154718579Sfenner	 * add back carry outs from top 16 bits to low 16 bits
154818579Sfenner	 */
154918579Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
155018579Sfenner	sum += (sum >> 16);			/* add carry */
155118579Sfenner	answer = ~sum;				/* truncate to 16 bits */
155218579Sfenner	return (answer);
155318579Sfenner}
155418579Sfenner
155518579Sfenner/*
155618579Sfenner * Subtract 2 timeval structs:  out = out - in.
155744086Sdes * Out is assumed to be within about LONG_MAX seconds of in.
155818579Sfenner */
155918579Sfennervoid
156018579Sfennertvsub(register struct timeval *out, register struct timeval *in)
156118579Sfenner{
156218579Sfenner
156318579Sfenner	if ((out->tv_usec -= in->tv_usec) < 0)   {
156418579Sfenner		--out->tv_sec;
156518579Sfenner		out->tv_usec += 1000000;
156618579Sfenner	}
156718579Sfenner	out->tv_sec -= in->tv_sec;
156818579Sfenner}
156918579Sfenner
157018579Sfenner/*
157118579Sfenner * Construct an Internet address representation.
157218579Sfenner * If the nflag has been supplied, give
157318579Sfenner * numeric value, otherwise try for symbolic name.
157418579Sfenner */
157518579Sfennerchar *
157618579Sfennerinetname(struct in_addr in)
157718579Sfenner{
157818579Sfenner	register char *cp;
157918579Sfenner	register struct hostent *hp;
158018579Sfenner	static int first = 1;
158118579Sfenner	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
158218579Sfenner
158318579Sfenner	if (first && !nflag) {
158418579Sfenner		first = 0;
1585100787Sfenner		if (gethostname(domain, sizeof(domain) - 1) < 0)
158618579Sfenner			domain[0] = '\0';
1587100787Sfenner		else {
1588100787Sfenner			cp = strchr(domain, '.');
1589100787Sfenner			if (cp == NULL) {
1590100787Sfenner				hp = gethostbyname(domain);
1591100787Sfenner				if (hp != NULL)
1592100787Sfenner					cp = strchr(hp->h_name, '.');
1593100787Sfenner			}
1594100787Sfenner			if (cp == NULL)
1595100787Sfenner				domain[0] = '\0';
1596100787Sfenner			else {
1597100787Sfenner				++cp;
1598100787Sfenner				(void)strncpy(domain, cp, sizeof(domain) - 1);
1599100787Sfenner				domain[sizeof(domain) - 1] = '\0';
1600100787Sfenner			}
1601100787Sfenner		}
160218579Sfenner	}
160318579Sfenner	if (!nflag && in.s_addr != INADDR_ANY) {
160418579Sfenner		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
160518579Sfenner		if (hp != NULL) {
160618579Sfenner			if ((cp = strchr(hp->h_name, '.')) != NULL &&
160718579Sfenner			    strcmp(cp + 1, domain) == 0)
160818579Sfenner				*cp = '\0';
160918579Sfenner			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
161018579Sfenner			line[sizeof(line) - 1] = '\0';
161118579Sfenner			return (line);
161218579Sfenner		}
161318579Sfenner	}
161418579Sfenner	return (inet_ntoa(in));
161518579Sfenner}
161618579Sfenner
1617100787Sfennerstruct hostinfo *
1618100787Sfennergethostinfo(register char *hostname)
161918579Sfenner{
1620100787Sfenner	register int n;
162118579Sfenner	register struct hostent *hp;
1622100787Sfenner	register struct hostinfo *hi;
1623100787Sfenner	register char **p;
1624100787Sfenner	register u_int32_t addr, *ap;
162518579Sfenner
1626100787Sfenner	if (strlen(hostname) > 64) {
1627100787Sfenner		Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1628100787Sfenner		    prog, hostname);
1629100787Sfenner		exit(1);
1630100787Sfenner	}
1631100787Sfenner	hi = calloc(1, sizeof(*hi));
1632100787Sfenner	if (hi == NULL) {
1633100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1634100787Sfenner		exit(1);
1635100787Sfenner	}
1636100787Sfenner	addr = inet_addr(hostname);
1637100787Sfenner	if ((int32_t)addr != -1) {
1638100787Sfenner		hi->name = strdup(hostname);
1639100787Sfenner		hi->n = 1;
1640100787Sfenner		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1641100787Sfenner		if (hi->addrs == NULL) {
1642100787Sfenner			Fprintf(stderr, "%s: calloc %s\n",
1643100787Sfenner			    prog, strerror(errno));
1644100787Sfenner			exit(1);
1645100787Sfenner		}
1646100787Sfenner		hi->addrs[0] = addr;
1647100787Sfenner		return (hi);
1648100787Sfenner	}
164918579Sfenner
165018579Sfenner	hp = gethostbyname(hostname);
165118579Sfenner	if (hp == NULL) {
165218579Sfenner		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
165318579Sfenner		exit(1);
165418579Sfenner	}
165518579Sfenner	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
165618579Sfenner		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
165718579Sfenner		exit(1);
165818579Sfenner	}
1659100787Sfenner	hi->name = strdup(hp->h_name);
1660100787Sfenner	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1661100787Sfenner		continue;
1662100787Sfenner	hi->n = n;
1663100787Sfenner	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1664100787Sfenner	if (hi->addrs == NULL) {
1665100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1666100787Sfenner		exit(1);
1667100787Sfenner	}
1668100787Sfenner	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1669100787Sfenner		memcpy(ap, *p, sizeof(*ap));
1670100787Sfenner	return (hi);
167118579Sfenner}
167218579Sfenner
1673100787Sfennervoid
1674100787Sfennerfreehostinfo(register struct hostinfo *hi)
167518579Sfenner{
1676100787Sfenner	if (hi->name != NULL) {
1677100787Sfenner		free(hi->name);
1678100787Sfenner		hi->name = NULL;
1679100787Sfenner	}
1680100787Sfenner	free((char *)hi->addrs);
1681100787Sfenner	free((char *)hi);
1682100787Sfenner}
168318579Sfenner
1684100787Sfennervoid
1685100787Sfennergetaddr(register u_int32_t *ap, register char *hostname)
1686100787Sfenner{
1687100787Sfenner	register struct hostinfo *hi;
1688100787Sfenner
1689100787Sfenner	hi = gethostinfo(hostname);
1690100787Sfenner	*ap = hi->addrs[0];
1691100787Sfenner	freehostinfo(hi);
1692100787Sfenner}
1693100787Sfenner
1694100787Sfennervoid
1695100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr)
1696100787Sfenner{
1697100787Sfenner
169818579Sfenner	memset(sin, 0, sizeof(*sin));
1699100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN
1700100787Sfenner	sin->sin_len = sizeof(*sin);
1701100787Sfenner#endif
170218579Sfenner	sin->sin_family = AF_INET;
1703100787Sfenner	sin->sin_addr.s_addr = addr;
170418579Sfenner}
170518579Sfenner
1706100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */
1707100787Sfennerint
1708100787Sfennerstr2val(register const char *str, register const char *what,
1709100787Sfenner    register int mi, register int ma)
171018579Sfenner{
1711100787Sfenner	register const char *cp;
1712100787Sfenner	register int val;
1713100787Sfenner	char *ep;
171418579Sfenner
1715100787Sfenner	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1716100787Sfenner		cp = str + 2;
1717100787Sfenner		val = (int)strtol(cp, &ep, 16);
1718100787Sfenner	} else
1719100787Sfenner		val = (int)strtol(str, &ep, 10);
1720100787Sfenner	if (*ep != '\0') {
1721100787Sfenner		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1722100787Sfenner		    prog, str, what);
172318579Sfenner		exit(1);
172418579Sfenner	}
1725100787Sfenner	if (val < mi && mi >= 0) {
1726100787Sfenner		if (mi == 0)
1727100787Sfenner			Fprintf(stderr, "%s: %s must be >= %d\n",
1728100787Sfenner			    prog, what, mi);
1729100787Sfenner		else
1730100787Sfenner			Fprintf(stderr, "%s: %s must be > %d\n",
1731100787Sfenner			    prog, what, mi - 1);
1732100787Sfenner		exit(1);
1733100787Sfenner	}
1734100787Sfenner	if (val > ma && ma >= 0) {
1735100787Sfenner		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1736100787Sfenner		exit(1);
1737100787Sfenner	}
1738100787Sfenner	return (val);
173918579Sfenner}
174018579Sfenner
1741100787Sfennerstruct outproto *
1742100787Sfennersetproto(char *pname)
1743100787Sfenner{
1744100787Sfenner	struct outproto *proto;
1745100787Sfenner	int i;
1746100787Sfenner
1747100787Sfenner	for (i = 0; protos[i].name != NULL; i++) {
1748100787Sfenner		if (strcasecmp(protos[i].name, pname) == 0) {
1749100787Sfenner			break;
1750100787Sfenner		}
1751100787Sfenner	}
1752100787Sfenner	proto = &protos[i];
1753100787Sfenner	if (proto->name == NULL) {	/* generic handler */
1754100787Sfenner		struct protoent *pe;
1755100787Sfenner		u_long pnum;
1756100787Sfenner
1757100787Sfenner		/* Determine the IP protocol number */
1758100787Sfenner		if ((pe = getprotobyname(pname)) != NULL)
1759100787Sfenner			pnum = pe->p_proto;
1760100787Sfenner		else
1761100787Sfenner			pnum = str2val(optarg, "proto number", 1, 255);
1762100787Sfenner		proto->num = pnum;
1763100787Sfenner	}
1764100787Sfenner	return proto;
1765100787Sfenner}
1766100787Sfenner
176767682Sobrienvoid
1768163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) {
1769163387Sdwmalone	int l;
1770163387Sdwmalone	int i;
1771163387Sdwmalone
1772163387Sdwmalone	for (i = 0; i < la; i++)
1773163387Sdwmalone		Printf("%02x", (unsigned int)a[i]);
1774163387Sdwmalone	Printf("\n");
1775163387Sdwmalone	l = (la <= lb) ? la : lb;
1776163387Sdwmalone	for (i = 0; i < l; i++)
1777163387Sdwmalone		if (a[i] == b[i])
1778163387Sdwmalone			Printf("__");
1779163387Sdwmalone		else
1780163387Sdwmalone			Printf("%02x", (unsigned int)b[i]);
1781163387Sdwmalone	for (; i < lb; i++)
1782163387Sdwmalone		Printf("%02x", (unsigned int)b[i]);
1783163387Sdwmalone	Printf("\n");
1784163387Sdwmalone}
1785163387Sdwmalone
1786163387Sdwmalone
1787163387Sdwmalonevoid
178818579Sfennerusage(void)
178918579Sfenner{
179018579Sfenner	extern char version[];
179118579Sfenner
179218579Sfenner	Fprintf(stderr, "Version %s\n", version);
1793100787Sfenner	Fprintf(stderr,
1794176428Srpaulo	    "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
1795100787Sfenner	    "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
1796176428Srpaulo	    "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog);
179718579Sfenner	exit(1);
179818579Sfenner}
1799