traceroute.c revision 216184
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 216184 2010-12-04 14:19:27Z uqs $";
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>
224100789Sfenner#include <netinet/tcpip.h>
22518579Sfenner
22618579Sfenner#include <arpa/inet.h>
22718579Sfenner
22858804Sshin#ifdef	IPSEC
22958804Sshin#include <net/route.h>
230171135Sgnn#include <netipsec/ipsec.h>	/* XXX */
23158804Sshin#endif	/* IPSEC */
23258804Sshin
23318579Sfenner#include <ctype.h>
234100787Sfenner#include <err.h>
23518579Sfenner#include <errno.h>
236100787Sfenner#include <fcntl.h>
23718579Sfenner#ifdef HAVE_MALLOC_H
23818579Sfenner#include <malloc.h>
23918579Sfenner#endif
24018579Sfenner#include <memory.h>
24118579Sfenner#include <netdb.h>
24218579Sfenner#include <stdio.h>
24318579Sfenner#include <stdlib.h>
24418579Sfenner#include <string.h>
24518579Sfenner#include <unistd.h>
24618579Sfenner
247100787Sfenner/* rfc1716 */
248100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB
249100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
250100787Sfenner#endif
251100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE
252100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
253100787Sfenner#endif
254100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
255100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
256100787Sfenner#endif
257100787Sfenner
258100787Sfenner#include "findsaddr.h"
259100787Sfenner#include "ifaddrlist.h"
260176428Srpaulo#include "as.h"
261100787Sfenner#include "traceroute.h"
262100787Sfenner
26318579Sfenner/* Maximum number of gateways (include room for one noop) */
26418579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
26518579Sfenner
26618579Sfenner#ifndef MAXHOSTNAMELEN
26718579Sfenner#define MAXHOSTNAMELEN	64
26818579Sfenner#endif
26918579Sfenner
27018579Sfenner#define Fprintf (void)fprintf
27118579Sfenner#define Printf (void)printf
27218579Sfenner
27346542Sarchie/* What a GRE packet header looks like */
27446542Sarchiestruct grehdr {
27546542Sarchie	u_int16_t   flags;
27646542Sarchie	u_int16_t   proto;
27746542Sarchie	u_int16_t   length;	/* PPTP version of these fields */
27846542Sarchie	u_int16_t   callId;
27946542Sarchie};
28046542Sarchie#ifndef IPPROTO_GRE
28146542Sarchie#define IPPROTO_GRE	47
28246542Sarchie#endif
28346542Sarchie
28446542Sarchie/* For GRE, we prepare what looks like a PPTP packet */
28546542Sarchie#define GRE_PPTP_PROTO	0x880b
28646542Sarchie
287100787Sfenner/* Host name and address list */
288100787Sfennerstruct hostinfo {
289100787Sfenner	char *name;
290100787Sfenner	int n;
291100787Sfenner	u_int32_t *addrs;
292100787Sfenner};
293100787Sfenner
29418579Sfenner/* Data section of the probe packet */
29518579Sfennerstruct outdata {
29618579Sfenner	u_char seq;		/* sequence number of this packet */
29718579Sfenner	u_char ttl;		/* ttl packet left with */
29818579Sfenner	struct timeval tv;	/* time packet left */
29918579Sfenner};
30018579Sfenner
301100787Sfenner#ifndef HAVE_ICMP_NEXTMTU
302100787Sfenner/* Path MTU Discovery (RFC1191) */
303100787Sfennerstruct my_pmtu {
304100787Sfenner	u_short ipm_void;
305100787Sfenner	u_short ipm_nextmtu;
30646542Sarchie};
307100787Sfenner#endif
30846542Sarchie
30918579Sfenneru_char	packet[512];		/* last inbound (icmp) packet */
31018579Sfenner
31146542Sarchiestruct ip *outip;		/* last output ip packet */
312100787Sfenneru_char *outp;		/* last output inner protocol packet */
31318579Sfenner
314163387Sdwmalonestruct ip *hip = NULL;		/* Quoted IP header */
315163387Sdwmaloneint hiplen = 0;
316163387Sdwmalone
31718579Sfenner/* loose source route gateway list (including room for final destination) */
31818579Sfenneru_int32_t gwlist[NGATEWAYS + 1];
31918579Sfenner
32018579Sfennerint s;				/* receive (icmp) socket file descriptor */
32118579Sfennerint sndsock;			/* send (udp) socket file descriptor */
32218579Sfenner
32318579Sfennerstruct sockaddr whereto;	/* Who to try to reach */
324100787Sfennerstruct sockaddr wherefrom;	/* Who we are */
32518579Sfennerint packlen;			/* total length of packet */
32646542Sarchieint protlen;			/* length of protocol part of packet */
327100787Sfennerint minpacket;			/* min ip packet size */
32818579Sfennerint maxpacket = 32 * 1024;	/* max ip packet size */
329100787Sfennerint pmtu;			/* Path MTU Discovery (RFC1191) */
330100787Sfenneru_int pausemsecs;
33118579Sfenner
33218579Sfennerchar *prog;
33318579Sfennerchar *source;
33418579Sfennerchar *hostname;
335100787Sfennerchar *device;
336100787Sfennerstatic const char devnull[] = "/dev/null";
33718579Sfenner
338163387Sdwmaloneint nprobes = -1;
33977816Sruint max_ttl;
340100787Sfennerint first_ttl = 1;
34118579Sfenneru_short ident;
34246542Sarchieu_short port;			/* protocol specific base "port" */
34318579Sfenner
34418579Sfennerint options;			/* socket options */
34518579Sfennerint verbose;
34618579Sfennerint waittime = 5;		/* time to wait for response (in seconds) */
34718579Sfennerint nflag;			/* print addresses numerically */
348176428Srpauloint as_path;			/* print as numbers for each hop */
349176428Srpaulochar *as_server = NULL;
350176428Srpaulovoid *asn;
351100787Sfenner#ifdef CANT_HACK_IPCKSUM
352100787Sfennerint doipcksum = 0;		/* don't calculate ip checksums by default */
353100787Sfenner#else
354100787Sfennerint doipcksum = 1;		/* calculate ip checksums by default */
355100787Sfenner#endif
356100787Sfennerint optlen;			/* length of ip options */
357158424Scjcint fixedPort = 0;		/* Use fixed destination port for TCP and UDP */
358163387Sdwmaloneint printdiff = 0;		/* Print the difference between sent and quoted */
35918579Sfenner
36018579Sfennerextern int optind;
36118579Sfennerextern int opterr;
36218579Sfennerextern char *optarg;
36318579Sfenner
36418579Sfenner/* Forwards */
36518579Sfennerdouble	deltaT(struct timeval *, struct timeval *);
366100787Sfennervoid	freehostinfo(struct hostinfo *);
367100787Sfennervoid	getaddr(u_int32_t *, char *);
368100787Sfennerstruct	hostinfo *gethostinfo(char *);
369100535Sfenneru_short	in_cksum(u_short *, int);
37018579Sfennerchar	*inetname(struct in_addr);
37118579Sfennerint	main(int, char **);
372100789Sfenneru_short p_cksum(struct ip *, u_short *, int);
37318579Sfennerint	packet_ok(u_char *, int, struct sockaddr_in *, int);
37418579Sfennerchar	*pr_type(u_char);
37518579Sfennervoid	print(u_char *, int, struct sockaddr_in *);
37658804Sshin#ifdef	IPSEC
37758804Sshinint	setpolicy __P((int so, char *policy));
37858804Sshin#endif
37946542Sarchievoid	send_probe(int, int);
380100787Sfennerstruct outproto *setproto(char *);
381100787Sfennerint	str2val(const char *, const char *, int, int);
38218579Sfennervoid	tvsub(struct timeval *, struct timeval *);
38367682Sobrienvoid usage(void);
384100787Sfennerint	wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
385163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int);
386100787Sfenner#ifndef HAVE_USLEEP
387100787Sfennerint	usleep(u_int);
388100787Sfenner#endif
38918579Sfenner
39046542Sarchievoid	udp_prep(struct outdata *);
39146542Sarchieint	udp_check(const u_char *, int);
39246542Sarchievoid	tcp_prep(struct outdata *);
39346542Sarchieint	tcp_check(const u_char *, int);
39446542Sarchievoid	gre_prep(struct outdata *);
39546542Sarchieint	gre_check(const u_char *, int);
39646542Sarchievoid	gen_prep(struct outdata *);
39746542Sarchieint	gen_check(const u_char *, int);
398100535Sfennervoid	icmp_prep(struct outdata *);
399100535Sfennerint	icmp_check(const u_char *, int);
40046542Sarchie
401100787Sfenner/* Descriptor structure for each outgoing protocol we support */
402100787Sfennerstruct outproto {
403100787Sfenner	char	*name;		/* name of protocol */
404163387Sdwmalone	const char *key;	/* An ascii key for the bytes of the header */
405100787Sfenner	u_char	num;		/* IP protocol number */
406100787Sfenner	u_short	hdrlen;		/* max size of protocol header */
407100787Sfenner	u_short	port;		/* default base protocol-specific "port" */
408100787Sfenner	void	(*prepare)(struct outdata *);
409100787Sfenner				/* finish preparing an outgoing packet */
410100787Sfenner	int	(*check)(const u_char *, int);
411100787Sfenner				/* check an incoming packet */
412100787Sfenner};
413100787Sfenner
41446542Sarchie/* List of supported protocols. The first one is the default. The last
41546542Sarchie   one is the handler for generic protocols not explicitly listed. */
41646542Sarchiestruct	outproto protos[] = {
41746542Sarchie	{
41846542Sarchie		"udp",
419163387Sdwmalone		"spt dpt len sum",
42046542Sarchie		IPPROTO_UDP,
42146542Sarchie		sizeof(struct udphdr),
42246542Sarchie		32768 + 666,
42346542Sarchie		udp_prep,
42446542Sarchie		udp_check
42546542Sarchie	},
42646542Sarchie	{
42746542Sarchie		"tcp",
428163387Sdwmalone		"spt dpt seq     ack     xxflwin sum urp",
42946542Sarchie		IPPROTO_TCP,
43046542Sarchie		sizeof(struct tcphdr),
43146542Sarchie		32768 + 666,
43246542Sarchie		tcp_prep,
43346542Sarchie		tcp_check
43446542Sarchie	},
43546542Sarchie	{
43646542Sarchie		"gre",
437163387Sdwmalone		"flg pro len clid",
43846542Sarchie		IPPROTO_GRE,
43946542Sarchie		sizeof(struct grehdr),
44046542Sarchie		GRE_PPTP_PROTO,
44146542Sarchie		gre_prep,
44246542Sarchie		gre_check
44346542Sarchie	},
44446542Sarchie	{
445100535Sfenner		"icmp",
446163387Sdwmalone		"typ cod sum ",
447100535Sfenner		IPPROTO_ICMP,
448100535Sfenner		sizeof(struct icmp),
449100535Sfenner		0,
450100535Sfenner		icmp_prep,
451100535Sfenner		icmp_check
452100535Sfenner	},
453100535Sfenner	{
45446542Sarchie		NULL,
455163387Sdwmalone		NULL,
45646542Sarchie		0,
45746542Sarchie		2 * sizeof(u_short),
45846542Sarchie		0,
45946542Sarchie		gen_prep,
46046542Sarchie		gen_check
46146542Sarchie	},
46246542Sarchie};
46346542Sarchiestruct	outproto *proto = &protos[0];
46446542Sarchie
465163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id  off tlprsum srcip   dstip   opts";
466163387Sdwmalone
46718579Sfennerint
46818579Sfennermain(int argc, char **argv)
46918579Sfenner{
470100787Sfenner	register int op, code, n;
47118579Sfenner	register char *cp;
472100787Sfenner	register const char *err;
473100787Sfenner	register u_int32_t *ap;
474100787Sfenner	register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
47518579Sfenner	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
476100787Sfenner	register struct hostinfo *hi;
47718579Sfenner	int on = 1;
47818579Sfenner	register struct protoent *pe;
47918579Sfenner	register int ttl, probe, i;
48018579Sfenner	register int seq = 0;
481100787Sfenner	int tos = 0, settos = 0;
48218579Sfenner	register int lsrr = 0;
483100787Sfenner	register u_short off = 0;
484100787Sfenner	struct ifaddrlist *al;
485100787Sfenner	char errbuf[132];
48648221Sarchie	int requestPort = -1;
48718803Ssef	int sump = 0;
48818583Sfenner	int sockerrno;
48918579Sfenner
490100787Sfenner	/* Insure the socket fds won't be 0, 1 or 2 */
491100787Sfenner	if (open(devnull, O_RDONLY) < 0 ||
492100787Sfenner	    open(devnull, O_RDONLY) < 0 ||
493100787Sfenner	    open(devnull, O_RDONLY) < 0) {
494100787Sfenner		Fprintf(stderr, "%s: open \"%s\": %s\n",
495100787Sfenner		    prog, devnull, strerror(errno));
496100787Sfenner		exit(1);
497100787Sfenner	}
49818583Sfenner	/*
49918583Sfenner	 * Do the setuid-required stuff first, then lose priveleges ASAP.
50018583Sfenner	 * Do error checking for these two calls where they appeared in
50118583Sfenner	 * the original code.
50218583Sfenner	 */
50318583Sfenner	cp = "icmp";
50418583Sfenner	pe = getprotobyname(cp);
50518583Sfenner	if (pe) {
50618583Sfenner		if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
50718583Sfenner			sockerrno = errno;
50818583Sfenner		else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
50918583Sfenner			sockerrno = errno;
51018583Sfenner	}
51118583Sfenner
51218583Sfenner	setuid(getuid());
51318583Sfenner
51477816Sru#ifdef IPCTL_DEFTTL
51577816Sru	{
51677816Sru		int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
51777816Sru		size_t sz = sizeof(max_ttl);
51877816Sru
519100787Sfenner		if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
520100787Sfenner			perror("sysctl(net.inet.ip.ttl)");
521100787Sfenner			exit(1);
522100787Sfenner		}
52377816Sru	}
52477816Sru#else
52577816Sru	max_ttl = 30;
52677816Sru#endif
52777816Sru
528100787Sfenner	if (argv[0] == NULL)
529100787Sfenner		prog = "traceroute";
530100787Sfenner	else if ((cp = strrchr(argv[0], '/')) != NULL)
53118579Sfenner		prog = cp + 1;
53218579Sfenner	else
53318579Sfenner		prog = argv[0];
53418579Sfenner
53518579Sfenner	opterr = 0;
536176428Srpaulo	while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
53718579Sfenner		switch (op) {
538176428Srpaulo		case 'a':
539176428Srpaulo			as_path = 1;
540176428Srpaulo			break;
541176428Srpaulo
542176428Srpaulo		case 'A':
543176428Srpaulo			as_path = 1;
544176428Srpaulo			as_server = optarg;
545176428Srpaulo			break;
546176428Srpaulo
54718579Sfenner		case 'd':
54818579Sfenner			options |= SO_DEBUG;
54918579Sfenner			break;
55018579Sfenner
551163387Sdwmalone		case 'D':
552163387Sdwmalone			printdiff = 1;
553163387Sdwmalone			break;
554163387Sdwmalone
555158424Scjc		case 'e':
556158424Scjc			fixedPort = 1;
557158424Scjc			break;
558158424Scjc
559100787Sfenner		case 'f':
560100787Sfenner		case 'M':	/* FreeBSD compat. */
561100787Sfenner			first_ttl = str2val(optarg, "first ttl", 1, 255);
562100787Sfenner			break;
563100787Sfenner
564100787Sfenner		case 'F':
565100787Sfenner			off = IP_DF;
566100787Sfenner			break;
567100787Sfenner
56818579Sfenner		case 'g':
56918579Sfenner			if (lsrr >= NGATEWAYS) {
57018579Sfenner				Fprintf(stderr,
57118579Sfenner				    "%s: No more than %d gateways\n",
57218579Sfenner				    prog, NGATEWAYS);
57318579Sfenner				exit(1);
57418579Sfenner			}
575100787Sfenner			getaddr(gwlist + lsrr, optarg);
57618579Sfenner			++lsrr;
57718579Sfenner			break;
57818579Sfenner
579100787Sfenner		case 'i':
580100787Sfenner			device = optarg;
58147071Sarchie			break;
58247071Sarchie
583100787Sfenner		case 'I':
584100787Sfenner			proto = setproto("icmp");
585100787Sfenner			break;
586100787Sfenner
58718579Sfenner		case 'm':
588100787Sfenner			max_ttl = str2val(optarg, "max ttl", 1, 255);
58918579Sfenner			break;
59018579Sfenner
59118579Sfenner		case 'n':
59218579Sfenner			++nflag;
59318579Sfenner			break;
59418579Sfenner
59546542Sarchie		case 'P':
596100787Sfenner			proto = setproto(optarg);
59746542Sarchie			break;
59846542Sarchie
59918579Sfenner		case 'p':
600100787Sfenner			requestPort = (u_short)str2val(optarg, "port",
601100787Sfenner			    1, (1 << 16) - 1);
60218579Sfenner			break;
60318579Sfenner
60418579Sfenner		case 'q':
605100787Sfenner			nprobes = str2val(optarg, "nprobes", 1, -1);
60618579Sfenner			break;
60718579Sfenner
60818579Sfenner		case 'r':
60918579Sfenner			options |= SO_DONTROUTE;
61018579Sfenner			break;
61118579Sfenner
61218579Sfenner		case 's':
61318579Sfenner			/*
61418579Sfenner			 * set the ip source address of the outbound
61518579Sfenner			 * probe (e.g., on a multi-homed host).
61618579Sfenner			 */
61718579Sfenner			source = optarg;
61818579Sfenner			break;
61918579Sfenner
620100787Sfenner		case 'S':
621100787Sfenner			sump = 1;
622100787Sfenner			break;
623100787Sfenner
62418579Sfenner		case 't':
625100787Sfenner			tos = str2val(optarg, "tos", 0, 255);
626100787Sfenner			++settos;
62718579Sfenner			break;
62818579Sfenner
62918579Sfenner		case 'v':
63018579Sfenner			++verbose;
63118579Sfenner			break;
63218579Sfenner
633100787Sfenner		case 'x':
634100787Sfenner			doipcksum = (doipcksum == 0);
635100787Sfenner			break;
636100787Sfenner
63718579Sfenner		case 'w':
638100787Sfenner			waittime = str2val(optarg, "wait time",
639169144Smaxim			    1, 24 * 60 * 60);
64018579Sfenner			break;
64118579Sfenner
642100787Sfenner		case 'z':
643100787Sfenner			pausemsecs = str2val(optarg, "pause msecs",
644100787Sfenner			    0, 60 * 60 * 1000);
645100787Sfenner			break;
646100787Sfenner
64718579Sfenner		default:
64818579Sfenner			usage();
64918579Sfenner		}
65018579Sfenner
65148221Sarchie	/* Set requested port, if any, else default for this protocol */
65248221Sarchie	port = (requestPort != -1) ? requestPort : proto->port;
65348221Sarchie
654163387Sdwmalone	if (nprobes == -1)
655163387Sdwmalone		nprobes = printdiff ? 1 : 3;
656163387Sdwmalone
657100787Sfenner	if (first_ttl > max_ttl) {
658100787Sfenner		Fprintf(stderr,
659100787Sfenner		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
660100787Sfenner		    prog, first_ttl, max_ttl);
66147071Sarchie		exit(1);
66247071Sarchie	}
66347071Sarchie
664100787Sfenner	if (!doipcksum)
665100787Sfenner		Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
666100787Sfenner
667100787Sfenner	if (lsrr > 0)
668100787Sfenner		optlen = (lsrr + 1) * sizeof(gwlist[0]);
669100787Sfenner	minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
670100787Sfenner	packlen = minpacket;			/* minimum sized packet */
671100787Sfenner
67218579Sfenner	/* Process destination and optional packet size */
67318579Sfenner	switch (argc - optind) {
67418579Sfenner
67518579Sfenner	case 2:
676100787Sfenner		packlen = str2val(argv[optind + 1],
677100787Sfenner		    "packet length", minpacket, maxpacket);
678100787Sfenner		/* Fall through */
67918579Sfenner
68018579Sfenner	case 1:
681100787Sfenner		hostname = argv[optind];
682100787Sfenner		hi = gethostinfo(hostname);
683100787Sfenner		setsin(to, hi->addrs[0]);
684100787Sfenner		if (hi->n > 1)
685100787Sfenner			Fprintf(stderr,
686100787Sfenner		    "%s: Warning: %s has multiple addresses; using %s\n",
687100787Sfenner				prog, hostname, inet_ntoa(to->sin_addr));
688100787Sfenner		hostname = hi->name;
689100787Sfenner		hi->name = NULL;
690100787Sfenner		freehostinfo(hi);
69118579Sfenner		break;
69218579Sfenner
69318579Sfenner	default:
69418579Sfenner		usage();
69518579Sfenner	}
69618579Sfenner
69718579Sfenner#ifdef HAVE_SETLINEBUF
69818579Sfenner	setlinebuf (stdout);
69918579Sfenner#else
70018579Sfenner	setvbuf(stdout, NULL, _IOLBF, 0);
70118579Sfenner#endif
70218579Sfenner
70346542Sarchie	protlen = packlen - sizeof(*outip) - optlen;
70418579Sfenner
70518579Sfenner	outip = (struct ip *)malloc((unsigned)packlen);
70618579Sfenner	if (outip == NULL) {
70718579Sfenner		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
70818579Sfenner		exit(1);
70918579Sfenner	}
71018579Sfenner	memset((char *)outip, 0, packlen);
71118579Sfenner
71218579Sfenner	outip->ip_v = IPVERSION;
713100787Sfenner	if (settos)
714100787Sfenner		outip->ip_tos = tos;
715100787Sfenner#ifdef BYTESWAP_IP_HDR
71618579Sfenner	outip->ip_len = htons(packlen);
717100787Sfenner	outip->ip_off = htons(off);
71818579Sfenner#else
71918579Sfenner	outip->ip_len = packlen;
720100787Sfenner	outip->ip_off = off;
72118579Sfenner#endif
72246542Sarchie	outip->ip_p = proto->num;
723100787Sfenner	outp = (u_char *)(outip + 1);
72418579Sfenner#ifdef HAVE_RAW_OPTIONS
72518579Sfenner	if (lsrr > 0) {
72618579Sfenner		register u_char *optlist;
72718579Sfenner
728100787Sfenner		optlist = outp;
729100787Sfenner		outp += optlen;
73018579Sfenner
73118579Sfenner		/* final hop */
73218579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
73318579Sfenner
73418579Sfenner		outip->ip_dst.s_addr = gwlist[0];
73518579Sfenner
73618579Sfenner		/* force 4 byte alignment */
73718579Sfenner		optlist[0] = IPOPT_NOP;
73818579Sfenner		/* loose source route option */
73918579Sfenner		optlist[1] = IPOPT_LSRR;
74018579Sfenner		i = lsrr * sizeof(gwlist[0]);
74118579Sfenner		optlist[2] = i + 3;
74218579Sfenner		/* Pointer to LSRR addresses */
74318579Sfenner		optlist[3] = IPOPT_MINOFF;
74418579Sfenner		memcpy(optlist + 4, gwlist + 1, i);
74518579Sfenner	} else
74618579Sfenner#endif
74718579Sfenner		outip->ip_dst = to->sin_addr;
74818579Sfenner
749100787Sfenner	outip->ip_hl = (outp - (u_char *)outip) >> 2;
75018579Sfenner	ident = (getpid() & 0xffff) | 0x8000;
75118579Sfenner
75218583Sfenner	if (pe == NULL) {
75318579Sfenner		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
75418579Sfenner		exit(1);
75518579Sfenner	}
75618583Sfenner	if (s < 0) {
75718583Sfenner		errno = sockerrno;
75818579Sfenner		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
75918579Sfenner		exit(1);
76018579Sfenner	}
76118579Sfenner	if (options & SO_DEBUG)
76218579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
76318579Sfenner		    sizeof(on));
76418579Sfenner	if (options & SO_DONTROUTE)
76518579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
76618579Sfenner		    sizeof(on));
76718579Sfenner
76858804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
76958804Sshin	if (setpolicy(s, "in bypass") < 0)
77066809Skris		errx(1, "%s", ipsec_strerror());
77158804Sshin
77258804Sshin	if (setpolicy(s, "out bypass") < 0)
77366809Skris		errx(1, "%s", ipsec_strerror());
77458804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
77558804Sshin
77618583Sfenner	if (sndsock < 0) {
77718583Sfenner		errno = sockerrno;
77818579Sfenner		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
77918579Sfenner		exit(1);
78018579Sfenner	}
78118579Sfenner
78218579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
78318579Sfenner	if (lsrr > 0) {
78418579Sfenner		u_char optlist[MAX_IPOPTLEN];
78518579Sfenner
78618579Sfenner		cp = "ip";
78718579Sfenner		if ((pe = getprotobyname(cp)) == NULL) {
78818579Sfenner			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
78918579Sfenner			exit(1);
79018579Sfenner		}
79118579Sfenner
79218579Sfenner		/* final hop */
79318579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
79418579Sfenner		++lsrr;
79518579Sfenner
79618579Sfenner		/* force 4 byte alignment */
79718579Sfenner		optlist[0] = IPOPT_NOP;
79818579Sfenner		/* loose source route option */
79918579Sfenner		optlist[1] = IPOPT_LSRR;
80018579Sfenner		i = lsrr * sizeof(gwlist[0]);
80118579Sfenner		optlist[2] = i + 3;
80218579Sfenner		/* Pointer to LSRR addresses */
80318579Sfenner		optlist[3] = IPOPT_MINOFF;
80418579Sfenner		memcpy(optlist + 4, gwlist, i);
80518579Sfenner
806100787Sfenner		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
807100787Sfenner		    (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
80818579Sfenner			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
80918579Sfenner			    prog, strerror(errno));
81018579Sfenner			exit(1);
81118579Sfenner		    }
81218579Sfenner	}
81318579Sfenner#endif
81418579Sfenner
81518579Sfenner#ifdef SO_SNDBUF
81618579Sfenner	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
81718579Sfenner	    sizeof(packlen)) < 0) {
81818579Sfenner		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
81918579Sfenner		exit(1);
82018579Sfenner	}
82118579Sfenner#endif
82218579Sfenner#ifdef IP_HDRINCL
82318579Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
82418579Sfenner	    sizeof(on)) < 0) {
82518579Sfenner		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
82618579Sfenner		exit(1);
82718579Sfenner	}
828100787Sfenner#else
829100787Sfenner#ifdef IP_TOS
830100787Sfenner	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
831100787Sfenner	    (char *)&tos, sizeof(tos)) < 0) {
832100787Sfenner		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
833100787Sfenner		    prog, tos, strerror(errno));
834100787Sfenner		exit(1);
835100787Sfenner	}
83618579Sfenner#endif
837100787Sfenner#endif
83818579Sfenner	if (options & SO_DEBUG)
83918579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
84018579Sfenner		    sizeof(on));
84118579Sfenner	if (options & SO_DONTROUTE)
84218579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
84318579Sfenner		    sizeof(on));
84418579Sfenner
845100787Sfenner	/* Get the interface address list */
846100787Sfenner	n = ifaddrlist(&al, errbuf);
847100787Sfenner	if (n < 0) {
848100787Sfenner		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
849100787Sfenner		exit(1);
850100787Sfenner	}
851100787Sfenner	if (n == 0) {
852100787Sfenner		Fprintf(stderr,
853100787Sfenner		    "%s: Can't find any network interfaces\n", prog);
854100787Sfenner		exit(1);
855100787Sfenner	}
856100787Sfenner
857100787Sfenner	/* Look for a specific device */
858100787Sfenner	if (device != NULL) {
859100787Sfenner		for (i = n; i > 0; --i, ++al)
860100787Sfenner			if (strcmp(device, al->device) == 0)
861100787Sfenner				break;
862100787Sfenner		if (i <= 0) {
863100787Sfenner			Fprintf(stderr, "%s: Can't find interface %.32s\n",
864100787Sfenner			    prog, device);
865100787Sfenner			exit(1);
86618579Sfenner		}
86718579Sfenner	}
86818579Sfenner
869100787Sfenner	/* Determine our source address */
870100787Sfenner	if (source == NULL) {
871100787Sfenner		/*
872100787Sfenner		 * If a device was specified, use the interface address.
873100787Sfenner		 * Otherwise, try to determine our source address.
874100787Sfenner		 */
875100787Sfenner		if (device != NULL)
876100787Sfenner			setsin(from, al->addr);
877100787Sfenner		else if ((err = findsaddr(to, from)) != NULL) {
878100787Sfenner			Fprintf(stderr, "%s: findsaddr: %s\n",
879100787Sfenner			    prog, err);
880100787Sfenner			exit(1);
881100787Sfenner		}
882100787Sfenner	} else {
883100787Sfenner		hi = gethostinfo(source);
884100787Sfenner		source = hi->name;
885100787Sfenner		hi->name = NULL;
886100787Sfenner		/*
887100787Sfenner		 * If the device was specified make sure it
888100787Sfenner		 * corresponds to the source address specified.
889100787Sfenner		 * Otherwise, use the first address (and warn if
890100787Sfenner		 * there are more than one).
891100787Sfenner		 */
892100787Sfenner		if (device != NULL) {
893100787Sfenner			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
894100787Sfenner				if (*ap == al->addr)
895100787Sfenner					break;
896100787Sfenner			if (i <= 0) {
897100787Sfenner				Fprintf(stderr,
898100787Sfenner				    "%s: %s is not on interface %.32s\n",
899100787Sfenner				    prog, source, device);
900100787Sfenner				exit(1);
901100787Sfenner			}
902100787Sfenner			setsin(from, *ap);
903100787Sfenner		} else {
904100787Sfenner			setsin(from, hi->addrs[0]);
905100787Sfenner			if (hi->n > 1)
906100787Sfenner				Fprintf(stderr,
907100787Sfenner			"%s: Warning: %s has multiple addresses; using %s\n",
908100787Sfenner				    prog, source, inet_ntoa(from->sin_addr));
909100787Sfenner		}
910100787Sfenner		freehostinfo(hi);
911100787Sfenner	}
912100787Sfenner
913100787Sfenner	outip->ip_src = from->sin_addr;
914128365Spb
915128365Spb	/* Check the source address (-s), if any, is valid */
916100787Sfenner	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
917100787Sfenner		Fprintf(stderr, "%s: bind: %s\n",
918100787Sfenner		    prog, strerror(errno));
919100787Sfenner		exit (1);
920100787Sfenner	}
921100787Sfenner
922176428Srpaulo	if (as_path) {
923176428Srpaulo		asn = as_setup(as_server);
924176428Srpaulo		if (asn == NULL) {
925176428Srpaulo			Fprintf(stderr, "%s: as_setup failed, AS# lookups"
926176428Srpaulo			    " disabled\n", prog);
927176428Srpaulo			(void)fflush(stderr);
928176428Srpaulo			as_path = 0;
929176428Srpaulo		}
930176428Srpaulo	}
931176428Srpaulo
93258804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
93358804Sshin	if (setpolicy(sndsock, "in bypass") < 0)
93466809Skris		errx(1, "%s", ipsec_strerror());
93558804Sshin
93658804Sshin	if (setpolicy(sndsock, "out bypass") < 0)
93766809Skris		errx(1, "%s", ipsec_strerror());
93858804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
93958804Sshin
94018579Sfenner	Fprintf(stderr, "%s to %s (%s)",
94118579Sfenner	    prog, hostname, inet_ntoa(to->sin_addr));
94218579Sfenner	if (source)
94318579Sfenner		Fprintf(stderr, " from %s", source);
94418579Sfenner	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
94518579Sfenner	(void)fflush(stderr);
94618579Sfenner
947100787Sfenner	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
94818579Sfenner		u_int32_t lastaddr = 0;
949100787Sfenner		int gotlastaddr = 0;
95018579Sfenner		int got_there = 0;
95118579Sfenner		int unreachable = 0;
952100787Sfenner		int sentfirst = 0;
95318695Ssef		int loss;
95418579Sfenner
95518579Sfenner		Printf("%2d ", ttl);
95618695Ssef		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
95718579Sfenner			register int cc;
95818579Sfenner			struct timeval t1, t2;
95918579Sfenner			register struct ip *ip;
96046542Sarchie			struct outdata outdata;
96118579Sfenner
962100787Sfenner			if (sentfirst && pausemsecs > 0)
963100787Sfenner				usleep(pausemsecs * 1000);
96446542Sarchie			/* Prepare outgoing data */
96546542Sarchie			outdata.seq = ++seq;
96646542Sarchie			outdata.ttl = ttl;
96746542Sarchie
96846542Sarchie			/* Avoid alignment problems by copying bytewise: */
969211062Sed			(void)gettimeofday(&t1, NULL);
97046542Sarchie			memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
97146542Sarchie
97246542Sarchie			/* Finalize and send packet */
97346542Sarchie			(*proto->prepare)(&outdata);
97446542Sarchie			send_probe(seq, ttl);
975100787Sfenner			++sentfirst;
97646542Sarchie
97746542Sarchie			/* Wait for a reply */
978100787Sfenner			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
97918583Sfenner				double T;
98018583Sfenner				int precis;
98118583Sfenner
982211062Sed				(void)gettimeofday(&t2, NULL);
983100787Sfenner				i = packet_ok(packet, cc, from, seq);
98418579Sfenner				/* Skip short packet */
98518579Sfenner				if (i == 0)
98618579Sfenner					continue;
987100787Sfenner				if (!gotlastaddr ||
988100787Sfenner				    from->sin_addr.s_addr != lastaddr) {
989154192Spav					if (gotlastaddr) printf("\n   ");
990100787Sfenner					print(packet, cc, from);
991100787Sfenner					lastaddr = from->sin_addr.s_addr;
992100787Sfenner					++gotlastaddr;
99318579Sfenner				}
99418583Sfenner				T = deltaT(&t1, &t2);
99518583Sfenner#ifdef SANE_PRECISION
99618583Sfenner				if (T >= 1000.0)
99718583Sfenner					precis = 0;
99818583Sfenner				else if (T >= 100.0)
99918583Sfenner					precis = 1;
100018583Sfenner				else if (T >= 10.0)
100118583Sfenner					precis = 2;
100218583Sfenner				else
100318583Sfenner#endif
100418583Sfenner					precis = 3;
100518583Sfenner				Printf("  %.*f ms", precis, T);
1006163387Sdwmalone				if (printdiff) {
1007163387Sdwmalone					Printf("\n");
1008163387Sdwmalone					Printf("%*.*s%s\n",
1009163387Sdwmalone					    -(outip->ip_hl << 3),
1010163387Sdwmalone					    outip->ip_hl << 3,
1011163387Sdwmalone					    ip_hdr_key,
1012163387Sdwmalone					    proto->key);
1013163387Sdwmalone					pkt_compare((void *)outip, packlen,
1014163387Sdwmalone					    (void *)hip, hiplen);
1015163387Sdwmalone				}
1016100535Sfenner				if (i == -2) {
1017100567Sdcs#ifndef ARCHAIC
1018100535Sfenner					ip = (struct ip *)packet;
1019100535Sfenner					if (ip->ip_ttl <= 1)
1020100535Sfenner						Printf(" !");
1021100535Sfenner#endif
1022100535Sfenner					++got_there;
1023100535Sfenner					break;
1024100535Sfenner				}
102518579Sfenner				/* time exceeded in transit */
102618579Sfenner				if (i == -1)
102718579Sfenner					break;
102818579Sfenner				code = i - 1;
102918579Sfenner				switch (code) {
103018579Sfenner
103118579Sfenner				case ICMP_UNREACH_PORT:
103218579Sfenner#ifndef ARCHAIC
103318579Sfenner					ip = (struct ip *)packet;
103418579Sfenner					if (ip->ip_ttl <= 1)
103518579Sfenner						Printf(" !");
103618579Sfenner#endif
103718579Sfenner					++got_there;
103818579Sfenner					break;
103918579Sfenner
104018579Sfenner				case ICMP_UNREACH_NET:
104118579Sfenner					++unreachable;
104218579Sfenner					Printf(" !N");
104318579Sfenner					break;
104418579Sfenner
104518579Sfenner				case ICMP_UNREACH_HOST:
104618579Sfenner					++unreachable;
104718579Sfenner					Printf(" !H");
104818579Sfenner					break;
104918579Sfenner
105018579Sfenner				case ICMP_UNREACH_PROTOCOL:
105118579Sfenner					++got_there;
105218579Sfenner					Printf(" !P");
105318579Sfenner					break;
105418579Sfenner
105518579Sfenner				case ICMP_UNREACH_NEEDFRAG:
105618579Sfenner					++unreachable;
1057100787Sfenner					Printf(" !F-%d", pmtu);
105818579Sfenner					break;
105918579Sfenner
106018579Sfenner				case ICMP_UNREACH_SRCFAIL:
106118579Sfenner					++unreachable;
106218579Sfenner					Printf(" !S");
106318579Sfenner					break;
106418579Sfenner
1065159576Sdwmalone				case ICMP_UNREACH_NET_UNKNOWN:
1066159576Sdwmalone					++unreachable;
1067159576Sdwmalone					Printf(" !U");
1068159576Sdwmalone					break;
1069159576Sdwmalone
1070159576Sdwmalone				case ICMP_UNREACH_HOST_UNKNOWN:
1071159576Sdwmalone					++unreachable;
1072159576Sdwmalone					Printf(" !W");
1073159576Sdwmalone					break;
1074159576Sdwmalone
1075159576Sdwmalone				case ICMP_UNREACH_ISOLATED:
1076159576Sdwmalone					++unreachable;
1077159576Sdwmalone					Printf(" !I");
1078159576Sdwmalone					break;
1079159576Sdwmalone
1080159576Sdwmalone				case ICMP_UNREACH_NET_PROHIB:
1081159576Sdwmalone					++unreachable;
1082159576Sdwmalone					Printf(" !A");
1083159576Sdwmalone					break;
1084159576Sdwmalone
1085159576Sdwmalone				case ICMP_UNREACH_HOST_PROHIB:
1086159576Sdwmalone					++unreachable;
1087159576Sdwmalone					Printf(" !Z");
1088159576Sdwmalone					break;
1089159576Sdwmalone
1090159576Sdwmalone				case ICMP_UNREACH_TOSNET:
1091159576Sdwmalone					++unreachable;
1092159576Sdwmalone					Printf(" !Q");
1093159576Sdwmalone					break;
1094159576Sdwmalone
1095159576Sdwmalone				case ICMP_UNREACH_TOSHOST:
1096159576Sdwmalone					++unreachable;
1097159576Sdwmalone					Printf(" !T");
1098159576Sdwmalone					break;
1099159576Sdwmalone
110018579Sfenner				case ICMP_UNREACH_FILTER_PROHIB:
110118579Sfenner					++unreachable;
110218579Sfenner					Printf(" !X");
110318579Sfenner					break;
110418579Sfenner
1105100787Sfenner				case ICMP_UNREACH_HOST_PRECEDENCE:
1106100787Sfenner					++unreachable;
1107100787Sfenner					Printf(" !V");
1108100787Sfenner					break;
1109100787Sfenner
1110100787Sfenner				case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1111100787Sfenner					++unreachable;
1112100787Sfenner					Printf(" !C");
1113100787Sfenner					break;
1114100787Sfenner
111518579Sfenner				default:
111618579Sfenner					++unreachable;
111718579Sfenner					Printf(" !<%d>", code);
111818579Sfenner					break;
111918579Sfenner				}
112018579Sfenner				break;
112118579Sfenner			}
112218695Ssef			if (cc == 0) {
112318695Ssef				loss++;
112418579Sfenner				Printf(" *");
112518695Ssef			}
112618579Sfenner			(void)fflush(stdout);
112718579Sfenner		}
112818803Ssef		if (sump) {
112918811Ssef			Printf(" (%d%% loss)", (loss * 100) / nprobes);
113018803Ssef		}
113118579Sfenner		putchar('\n');
113218579Sfenner		if (got_there ||
113318579Sfenner		    (unreachable > 0 && unreachable >= nprobes - 1))
113418579Sfenner			break;
113518579Sfenner	}
1136176428Srpaulo	if (as_path)
1137176428Srpaulo		as_shutdown(asn);
113818579Sfenner	exit(0);
113918579Sfenner}
114018579Sfenner
114118579Sfennerint
114218579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp,
1143100787Sfenner    register const struct timeval *tp)
114418579Sfenner{
114566810Skris	fd_set *fdsp;
114666810Skris	size_t nfds;
114718579Sfenner	struct timeval now, wait;
114818579Sfenner	register int cc = 0;
114944086Sdes	register int error;
115018579Sfenner	int fromlen = sizeof(*fromp);
115118579Sfenner
115266810Skris	nfds = howmany(sock + 1, NFDBITS);
115398709Srobert	if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
115466810Skris		err(1, "malloc");
115598709Srobert	memset(fdsp, 0, nfds * sizeof(fd_mask));
115666810Skris	FD_SET(sock, fdsp);
115718579Sfenner
115818579Sfenner	wait.tv_sec = tp->tv_sec + waittime;
115918579Sfenner	wait.tv_usec = tp->tv_usec;
1160211062Sed	(void)gettimeofday(&now, NULL);
116118579Sfenner	tvsub(&wait, &now);
116244086Sdes	if (wait.tv_sec < 0) {
116344086Sdes		wait.tv_sec = 0;
116444086Sdes		wait.tv_usec = 1;
116544086Sdes	}
116618579Sfenner
116766810Skris	error = select(sock + 1, fdsp, NULL, NULL, &wait);
116844086Sdes	if (error == -1 && errno == EINVAL) {
116944086Sdes		Fprintf(stderr, "%s: botched select() args\n", prog);
117044086Sdes		exit(1);
117144086Sdes	}
117244086Sdes	if (error > 0)
1173100787Sfenner		cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
117418579Sfenner			    (struct sockaddr *)fromp, &fromlen);
117518579Sfenner
117666810Skris	free(fdsp);
117718579Sfenner	return(cc);
117818579Sfenner}
117918579Sfenner
1180100787Sfennervoid
1181100787Sfennersend_probe(int seq, int ttl)
1182100787Sfenner{
1183100787Sfenner	register int cc;
1184100787Sfenner
1185100787Sfenner	outip->ip_ttl = ttl;
1186100787Sfenner	outip->ip_id = htons(ident + seq);
1187100787Sfenner
1188100787Sfenner	/* XXX undocumented debugging hack */
1189100787Sfenner	if (verbose > 1) {
1190100787Sfenner		register const u_short *sp;
1191100787Sfenner		register int nshorts, i;
1192100787Sfenner
1193100787Sfenner		sp = (u_short *)outip;
1194100787Sfenner		nshorts = (u_int)packlen / sizeof(u_short);
1195100787Sfenner		i = 0;
1196100787Sfenner		Printf("[ %d bytes", packlen);
1197100787Sfenner		while (--nshorts >= 0) {
1198100787Sfenner			if ((i++ % 8) == 0)
1199100787Sfenner				Printf("\n\t");
1200100787Sfenner			Printf(" %04x", ntohs(*sp++));
1201100787Sfenner		}
1202100787Sfenner		if (packlen & 1) {
1203100787Sfenner			if ((i % 8) == 0)
1204100787Sfenner				Printf("\n\t");
1205100787Sfenner			Printf(" %02x", *(u_char *)sp);
1206100787Sfenner		}
1207100787Sfenner		Printf("]\n");
1208100787Sfenner	}
1209100787Sfenner
1210100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL)
1211100787Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1212100787Sfenner	    (char *)&ttl, sizeof(ttl)) < 0) {
1213100787Sfenner		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1214100787Sfenner		    prog, ttl, strerror(errno));
1215100787Sfenner		exit(1);
1216100787Sfenner	}
1217100787Sfenner#endif
1218100787Sfenner
1219100787Sfenner	cc = sendto(sndsock, (char *)outip,
1220100787Sfenner	    packlen, 0, &whereto, sizeof(whereto));
1221100787Sfenner	if (cc < 0 || cc != packlen)  {
1222100787Sfenner		if (cc < 0)
1223100787Sfenner			Fprintf(stderr, "%s: sendto: %s\n",
1224100787Sfenner			    prog, strerror(errno));
1225100787Sfenner		Printf("%s: wrote %s %d chars, ret=%d\n",
1226100787Sfenner		    prog, hostname, packlen, cc);
1227100787Sfenner		(void)fflush(stdout);
1228100787Sfenner	}
1229100787Sfenner}
1230100787Sfenner
123158804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
123258804Sshinint
123358804Sshinsetpolicy(so, policy)
123458804Sshin	int so;
123558804Sshin	char *policy;
123658804Sshin{
123758804Sshin	char *buf;
123858804Sshin
123958804Sshin	buf = ipsec_set_policy(policy, strlen(policy));
124058804Sshin	if (buf == NULL) {
124166809Skris		warnx("%s", ipsec_strerror());
124258804Sshin		return -1;
124358804Sshin	}
124458804Sshin	(void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
124558804Sshin		buf, ipsec_get_policylen(buf));
124658804Sshin
124758804Sshin	free(buf);
124858804Sshin
124958804Sshin	return 0;
125058804Sshin}
125158804Sshin#endif
125258804Sshin
125318579Sfennerdouble
125418579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p)
125518579Sfenner{
125618579Sfenner	register double dt;
125718579Sfenner
125818579Sfenner	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
125918579Sfenner	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
126018579Sfenner	return (dt);
126118579Sfenner}
126218579Sfenner
126318579Sfenner/*
126418579Sfenner * Convert an ICMP "type" field to a printable string.
126518579Sfenner */
126618579Sfennerchar *
126718579Sfennerpr_type(register u_char t)
126818579Sfenner{
126918579Sfenner	static char *ttab[] = {
127018579Sfenner	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
127118579Sfenner	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
127218579Sfenner	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
127318579Sfenner	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
127418579Sfenner	"Info Reply"
127518579Sfenner	};
127618579Sfenner
127718579Sfenner	if (t > 16)
127818579Sfenner		return("OUT-OF-RANGE");
127918579Sfenner
128018579Sfenner	return(ttab[t]);
128118579Sfenner}
128218579Sfenner
128318579Sfennerint
128418579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
128518579Sfenner    register int seq)
128618579Sfenner{
128718579Sfenner	register struct icmp *icp;
128818579Sfenner	register u_char type, code;
128918579Sfenner	register int hlen;
129018579Sfenner#ifndef ARCHAIC
129118579Sfenner	register struct ip *ip;
129218579Sfenner
129318579Sfenner	ip = (struct ip *) buf;
129418579Sfenner	hlen = ip->ip_hl << 2;
129518579Sfenner	if (cc < hlen + ICMP_MINLEN) {
129618579Sfenner		if (verbose)
129718579Sfenner			Printf("packet too short (%d bytes) from %s\n", cc,
129818579Sfenner				inet_ntoa(from->sin_addr));
129918579Sfenner		return (0);
130018579Sfenner	}
130118579Sfenner	cc -= hlen;
130218579Sfenner	icp = (struct icmp *)(buf + hlen);
130318579Sfenner#else
130418579Sfenner	icp = (struct icmp *)buf;
130518579Sfenner#endif
130618579Sfenner	type = icp->icmp_type;
130718579Sfenner	code = icp->icmp_code;
1308100787Sfenner	/* Path MTU Discovery (RFC1191) */
1309100787Sfenner	if (code != ICMP_UNREACH_NEEDFRAG)
1310100787Sfenner		pmtu = 0;
1311100787Sfenner	else {
1312100787Sfenner#ifdef HAVE_ICMP_NEXTMTU
1313100787Sfenner		pmtu = ntohs(icp->icmp_nextmtu);
1314100787Sfenner#else
1315100787Sfenner		pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1316100787Sfenner#endif
1317100787Sfenner	}
1318100535Sfenner	if (type == ICMP_ECHOREPLY
1319100535Sfenner	    && proto->num == IPPROTO_ICMP
1320124859Scperciva	    && (*proto->check)((u_char *)icp, (u_char)seq))
1321100535Sfenner		return -2;
132218579Sfenner	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
132318579Sfenner	    type == ICMP_UNREACH) {
132446542Sarchie		u_char *inner;
132518579Sfenner
132618579Sfenner		hip = &icp->icmp_ip;
1327163387Sdwmalone		hiplen = ((u_char *)icp + cc) - (u_char *)hip;
132818579Sfenner		hlen = hip->ip_hl << 2;
132946542Sarchie		inner = (u_char *)((u_char *)hip + hlen);
133046542Sarchie		if (hlen + 12 <= cc
133146542Sarchie		    && hip->ip_p == proto->num
1332124859Scperciva		    && (*proto->check)(inner, (u_char)seq))
133318579Sfenner			return (type == ICMP_TIMXCEED ? -1 : code + 1);
133418579Sfenner	}
133518579Sfenner#ifndef ARCHAIC
133618579Sfenner	if (verbose) {
133718579Sfenner		register int i;
133818579Sfenner		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
133918579Sfenner
134018579Sfenner		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
134118579Sfenner		Printf("%s: icmp type %d (%s) code %d\n",
134218579Sfenner		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
134318579Sfenner		for (i = 4; i < cc ; i += sizeof(*lp))
134418579Sfenner			Printf("%2d: x%8.8x\n", i, *lp++);
134518579Sfenner	}
134618579Sfenner#endif
134718579Sfenner	return(0);
134818579Sfenner}
134918579Sfenner
135046542Sarchievoid
1351100535Sfennericmp_prep(struct outdata *outdata)
1352100535Sfenner{
1353100787Sfenner	struct icmp *const icmpheader = (struct icmp *) outp;
1354100535Sfenner
1355100535Sfenner	icmpheader->icmp_type = ICMP_ECHO;
1356100535Sfenner	icmpheader->icmp_id = htons(ident);
1357100535Sfenner	icmpheader->icmp_seq = htons(outdata->seq);
1358100535Sfenner	icmpheader->icmp_cksum = 0;
1359100789Sfenner	icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
1360100535Sfenner	if (icmpheader->icmp_cksum == 0)
1361100535Sfenner		icmpheader->icmp_cksum = 0xffff;
1362100535Sfenner}
1363100535Sfenner
1364100535Sfennerint
1365100535Sfennericmp_check(const u_char *data, int seq)
1366100535Sfenner{
1367100535Sfenner	struct icmp *const icmpheader = (struct icmp *) data;
1368100535Sfenner
1369100535Sfenner	return (icmpheader->icmp_id == htons(ident)
1370100535Sfenner	    && icmpheader->icmp_seq == htons(seq));
1371100535Sfenner}
1372100535Sfenner
1373100535Sfennervoid
137446542Sarchieudp_prep(struct outdata *outdata)
137546542Sarchie{
1376100787Sfenner	struct udphdr *const outudp = (struct udphdr *) outp;
137718579Sfenner
1378158424Scjc	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1379158424Scjc	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1380100787Sfenner	outudp->uh_ulen = htons((u_short)protlen);
1381100789Sfenner	outudp->uh_sum = 0;
1382100787Sfenner	if (doipcksum) {
1383100789Sfenner	    u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
1384100789Sfenner	    outudp->uh_sum = (sum) ? sum : 0xffff;
1385100787Sfenner	}
1386100789Sfenner
1387100789Sfenner	return;
138846542Sarchie}
138946542Sarchie
139046542Sarchieint
139146542Sarchieudp_check(const u_char *data, int seq)
139246542Sarchie{
139346542Sarchie	struct udphdr *const udp = (struct udphdr *) data;
139446542Sarchie
1395158424Scjc	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1396158424Scjc	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
139746542Sarchie}
139846542Sarchie
139918579Sfennervoid
140046542Sarchietcp_prep(struct outdata *outdata)
140146542Sarchie{
1402100787Sfenner	struct tcphdr *const tcp = (struct tcphdr *) outp;
140346542Sarchie
140446542Sarchie	tcp->th_sport = htons(ident);
1405158424Scjc	tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1406158424Scjc	tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
1407158424Scjc	    (fixedPort ? outdata->seq : 0));
140846542Sarchie	tcp->th_ack = 0;
140946542Sarchie	tcp->th_off = 5;
141046542Sarchie	tcp->th_flags = TH_SYN;
1411100789Sfenner	tcp->th_sum = 0;
1412100789Sfenner
1413100789Sfenner	if (doipcksum) {
1414100789Sfenner	    u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
1415100789Sfenner	    tcp->th_sum = (sum) ? sum : 0xffff;
1416100789Sfenner	}
141746542Sarchie}
141846542Sarchie
141946542Sarchieint
142046542Sarchietcp_check(const u_char *data, int seq)
142146542Sarchie{
142246542Sarchie	struct tcphdr *const tcp = (struct tcphdr *) data;
142346542Sarchie
142446542Sarchie	return (ntohs(tcp->th_sport) == ident
1425158424Scjc	    && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
1426216184Suqs	    && tcp->th_seq == (((tcp_seq)ident << 16) | (port + seq));
142746542Sarchie}
142846542Sarchie
142946542Sarchievoid
143046542Sarchiegre_prep(struct outdata *outdata)
143146542Sarchie{
1432100787Sfenner	struct grehdr *const gre = (struct grehdr *) outp;
143346542Sarchie
143446542Sarchie	gre->flags = htons(0x2001);
143546542Sarchie	gre->proto = htons(port);
143646542Sarchie	gre->length = 0;
143746542Sarchie	gre->callId = htons(ident + outdata->seq);
143846542Sarchie}
143946542Sarchie
144046542Sarchieint
144146542Sarchiegre_check(const u_char *data, int seq)
144246542Sarchie{
144346542Sarchie	struct grehdr *const gre = (struct grehdr *) data;
144446542Sarchie
144546542Sarchie	return(ntohs(gre->proto) == port
144646542Sarchie	    && ntohs(gre->callId) == ident + seq);
144746542Sarchie}
144846542Sarchie
144946542Sarchievoid
145046542Sarchiegen_prep(struct outdata *outdata)
145146542Sarchie{
1452100787Sfenner	u_int16_t *const ptr = (u_int16_t *) outp;
145346542Sarchie
145446542Sarchie	ptr[0] = htons(ident);
145546542Sarchie	ptr[1] = htons(port + outdata->seq);
145646542Sarchie}
145746542Sarchie
145846542Sarchieint
145946542Sarchiegen_check(const u_char *data, int seq)
146046542Sarchie{
146146542Sarchie	u_int16_t *const ptr = (u_int16_t *) data;
146246542Sarchie
146346542Sarchie	return(ntohs(ptr[0]) == ident
146446542Sarchie	    && ntohs(ptr[1]) == port + seq);
146546542Sarchie}
146646542Sarchie
146746542Sarchievoid
146818579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from)
146918579Sfenner{
147018579Sfenner	register struct ip *ip;
147118579Sfenner	register int hlen;
1472196475Sume	char addr[INET_ADDRSTRLEN];
147318579Sfenner
147418579Sfenner	ip = (struct ip *) buf;
147518579Sfenner	hlen = ip->ip_hl << 2;
147618579Sfenner	cc -= hlen;
147718579Sfenner
1478196475Sume	strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
1479196475Sume
1480176428Srpaulo	if (as_path)
1481196475Sume		Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
1482176428Srpaulo
148318579Sfenner	if (nflag)
1484196475Sume		Printf(" %s", addr);
148518579Sfenner	else
1486196475Sume		Printf(" %s (%s)", inetname(from->sin_addr), addr);
148718579Sfenner
148818579Sfenner	if (verbose)
148918579Sfenner		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
149018579Sfenner}
149118579Sfenner
149218579Sfenner/*
1493100789Sfenner * Checksum routine for UDP and TCP headers.
1494100789Sfenner */
1495100789Sfenneru_short
1496100789Sfennerp_cksum(struct ip *ip, u_short *data, int len)
1497100789Sfenner{
1498100789Sfenner	static struct ipovly ipo;
1499216184Suqs	u_short sum[2];
1500100789Sfenner
1501100789Sfenner	ipo.ih_pr = ip->ip_p;
1502100789Sfenner	ipo.ih_len = htons(len);
1503100789Sfenner	ipo.ih_src = ip->ip_src;
1504100789Sfenner	ipo.ih_dst = ip->ip_dst;
1505100789Sfenner
1506216184Suqs	sum[1] = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
1507216184Suqs	sum[0] = in_cksum(data, len);                   /* payload data cksum */
1508100789Sfenner
1509216184Suqs	return ~in_cksum(sum, sizeof(sum));
1510100789Sfenner}
1511100789Sfenner
1512100789Sfenner/*
151318579Sfenner * Checksum routine for Internet Protocol family headers (C Version)
151418579Sfenner */
1515100535Sfenneru_short
151618579Sfennerin_cksum(register u_short *addr, register int len)
151718579Sfenner{
151818579Sfenner	register int nleft = len;
151918579Sfenner	register u_short *w = addr;
152018579Sfenner	register u_short answer;
152118579Sfenner	register int sum = 0;
152218579Sfenner
152318579Sfenner	/*
152418579Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
152518579Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
152618579Sfenner	 *  back all the carry bits from the top 16 bits into the lower
152718579Sfenner	 *  16 bits.
152818579Sfenner	 */
152918579Sfenner	while (nleft > 1)  {
153018579Sfenner		sum += *w++;
153118579Sfenner		nleft -= 2;
153218579Sfenner	}
153318579Sfenner
153418579Sfenner	/* mop up an odd byte, if necessary */
153518579Sfenner	if (nleft == 1)
153618579Sfenner		sum += *(u_char *)w;
153718579Sfenner
153818579Sfenner	/*
153918579Sfenner	 * add back carry outs from top 16 bits to low 16 bits
154018579Sfenner	 */
154118579Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
154218579Sfenner	sum += (sum >> 16);			/* add carry */
154318579Sfenner	answer = ~sum;				/* truncate to 16 bits */
154418579Sfenner	return (answer);
154518579Sfenner}
154618579Sfenner
154718579Sfenner/*
154818579Sfenner * Subtract 2 timeval structs:  out = out - in.
154944086Sdes * Out is assumed to be within about LONG_MAX seconds of in.
155018579Sfenner */
155118579Sfennervoid
155218579Sfennertvsub(register struct timeval *out, register struct timeval *in)
155318579Sfenner{
155418579Sfenner
155518579Sfenner	if ((out->tv_usec -= in->tv_usec) < 0)   {
155618579Sfenner		--out->tv_sec;
155718579Sfenner		out->tv_usec += 1000000;
155818579Sfenner	}
155918579Sfenner	out->tv_sec -= in->tv_sec;
156018579Sfenner}
156118579Sfenner
156218579Sfenner/*
156318579Sfenner * Construct an Internet address representation.
156418579Sfenner * If the nflag has been supplied, give
156518579Sfenner * numeric value, otherwise try for symbolic name.
156618579Sfenner */
156718579Sfennerchar *
156818579Sfennerinetname(struct in_addr in)
156918579Sfenner{
157018579Sfenner	register char *cp;
157118579Sfenner	register struct hostent *hp;
157218579Sfenner	static int first = 1;
157318579Sfenner	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
157418579Sfenner
157518579Sfenner	if (first && !nflag) {
157618579Sfenner		first = 0;
1577100787Sfenner		if (gethostname(domain, sizeof(domain) - 1) < 0)
157818579Sfenner			domain[0] = '\0';
1579100787Sfenner		else {
1580100787Sfenner			cp = strchr(domain, '.');
1581100787Sfenner			if (cp == NULL) {
1582100787Sfenner				hp = gethostbyname(domain);
1583100787Sfenner				if (hp != NULL)
1584100787Sfenner					cp = strchr(hp->h_name, '.');
1585100787Sfenner			}
1586100787Sfenner			if (cp == NULL)
1587100787Sfenner				domain[0] = '\0';
1588100787Sfenner			else {
1589100787Sfenner				++cp;
1590100787Sfenner				(void)strncpy(domain, cp, sizeof(domain) - 1);
1591100787Sfenner				domain[sizeof(domain) - 1] = '\0';
1592100787Sfenner			}
1593100787Sfenner		}
159418579Sfenner	}
159518579Sfenner	if (!nflag && in.s_addr != INADDR_ANY) {
159618579Sfenner		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
159718579Sfenner		if (hp != NULL) {
159818579Sfenner			if ((cp = strchr(hp->h_name, '.')) != NULL &&
159918579Sfenner			    strcmp(cp + 1, domain) == 0)
160018579Sfenner				*cp = '\0';
160118579Sfenner			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
160218579Sfenner			line[sizeof(line) - 1] = '\0';
160318579Sfenner			return (line);
160418579Sfenner		}
160518579Sfenner	}
160618579Sfenner	return (inet_ntoa(in));
160718579Sfenner}
160818579Sfenner
1609100787Sfennerstruct hostinfo *
1610100787Sfennergethostinfo(register char *hostname)
161118579Sfenner{
1612100787Sfenner	register int n;
161318579Sfenner	register struct hostent *hp;
1614100787Sfenner	register struct hostinfo *hi;
1615100787Sfenner	register char **p;
1616100787Sfenner	register u_int32_t addr, *ap;
161718579Sfenner
1618100787Sfenner	if (strlen(hostname) > 64) {
1619100787Sfenner		Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1620100787Sfenner		    prog, hostname);
1621100787Sfenner		exit(1);
1622100787Sfenner	}
1623100787Sfenner	hi = calloc(1, sizeof(*hi));
1624100787Sfenner	if (hi == NULL) {
1625100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1626100787Sfenner		exit(1);
1627100787Sfenner	}
1628100787Sfenner	addr = inet_addr(hostname);
1629100787Sfenner	if ((int32_t)addr != -1) {
1630100787Sfenner		hi->name = strdup(hostname);
1631100787Sfenner		hi->n = 1;
1632100787Sfenner		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1633100787Sfenner		if (hi->addrs == NULL) {
1634100787Sfenner			Fprintf(stderr, "%s: calloc %s\n",
1635100787Sfenner			    prog, strerror(errno));
1636100787Sfenner			exit(1);
1637100787Sfenner		}
1638100787Sfenner		hi->addrs[0] = addr;
1639100787Sfenner		return (hi);
1640100787Sfenner	}
164118579Sfenner
164218579Sfenner	hp = gethostbyname(hostname);
164318579Sfenner	if (hp == NULL) {
164418579Sfenner		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
164518579Sfenner		exit(1);
164618579Sfenner	}
164718579Sfenner	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
164818579Sfenner		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
164918579Sfenner		exit(1);
165018579Sfenner	}
1651100787Sfenner	hi->name = strdup(hp->h_name);
1652100787Sfenner	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1653100787Sfenner		continue;
1654100787Sfenner	hi->n = n;
1655100787Sfenner	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1656100787Sfenner	if (hi->addrs == NULL) {
1657100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1658100787Sfenner		exit(1);
1659100787Sfenner	}
1660100787Sfenner	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1661100787Sfenner		memcpy(ap, *p, sizeof(*ap));
1662100787Sfenner	return (hi);
166318579Sfenner}
166418579Sfenner
1665100787Sfennervoid
1666100787Sfennerfreehostinfo(register struct hostinfo *hi)
166718579Sfenner{
1668100787Sfenner	if (hi->name != NULL) {
1669100787Sfenner		free(hi->name);
1670100787Sfenner		hi->name = NULL;
1671100787Sfenner	}
1672100787Sfenner	free((char *)hi->addrs);
1673100787Sfenner	free((char *)hi);
1674100787Sfenner}
167518579Sfenner
1676100787Sfennervoid
1677100787Sfennergetaddr(register u_int32_t *ap, register char *hostname)
1678100787Sfenner{
1679100787Sfenner	register struct hostinfo *hi;
1680100787Sfenner
1681100787Sfenner	hi = gethostinfo(hostname);
1682100787Sfenner	*ap = hi->addrs[0];
1683100787Sfenner	freehostinfo(hi);
1684100787Sfenner}
1685100787Sfenner
1686100787Sfennervoid
1687100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr)
1688100787Sfenner{
1689100787Sfenner
169018579Sfenner	memset(sin, 0, sizeof(*sin));
1691100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN
1692100787Sfenner	sin->sin_len = sizeof(*sin);
1693100787Sfenner#endif
169418579Sfenner	sin->sin_family = AF_INET;
1695100787Sfenner	sin->sin_addr.s_addr = addr;
169618579Sfenner}
169718579Sfenner
1698100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */
1699100787Sfennerint
1700100787Sfennerstr2val(register const char *str, register const char *what,
1701100787Sfenner    register int mi, register int ma)
170218579Sfenner{
1703100787Sfenner	register const char *cp;
1704100787Sfenner	register int val;
1705100787Sfenner	char *ep;
170618579Sfenner
1707100787Sfenner	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1708100787Sfenner		cp = str + 2;
1709100787Sfenner		val = (int)strtol(cp, &ep, 16);
1710100787Sfenner	} else
1711100787Sfenner		val = (int)strtol(str, &ep, 10);
1712100787Sfenner	if (*ep != '\0') {
1713100787Sfenner		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1714100787Sfenner		    prog, str, what);
171518579Sfenner		exit(1);
171618579Sfenner	}
1717100787Sfenner	if (val < mi && mi >= 0) {
1718100787Sfenner		if (mi == 0)
1719100787Sfenner			Fprintf(stderr, "%s: %s must be >= %d\n",
1720100787Sfenner			    prog, what, mi);
1721100787Sfenner		else
1722100787Sfenner			Fprintf(stderr, "%s: %s must be > %d\n",
1723100787Sfenner			    prog, what, mi - 1);
1724100787Sfenner		exit(1);
1725100787Sfenner	}
1726100787Sfenner	if (val > ma && ma >= 0) {
1727100787Sfenner		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1728100787Sfenner		exit(1);
1729100787Sfenner	}
1730100787Sfenner	return (val);
173118579Sfenner}
173218579Sfenner
1733100787Sfennerstruct outproto *
1734100787Sfennersetproto(char *pname)
1735100787Sfenner{
1736100787Sfenner	struct outproto *proto;
1737100787Sfenner	int i;
1738100787Sfenner
1739100787Sfenner	for (i = 0; protos[i].name != NULL; i++) {
1740100787Sfenner		if (strcasecmp(protos[i].name, pname) == 0) {
1741100787Sfenner			break;
1742100787Sfenner		}
1743100787Sfenner	}
1744100787Sfenner	proto = &protos[i];
1745100787Sfenner	if (proto->name == NULL) {	/* generic handler */
1746100787Sfenner		struct protoent *pe;
1747100787Sfenner		u_long pnum;
1748100787Sfenner
1749100787Sfenner		/* Determine the IP protocol number */
1750100787Sfenner		if ((pe = getprotobyname(pname)) != NULL)
1751100787Sfenner			pnum = pe->p_proto;
1752100787Sfenner		else
1753100787Sfenner			pnum = str2val(optarg, "proto number", 1, 255);
1754100787Sfenner		proto->num = pnum;
1755100787Sfenner	}
1756100787Sfenner	return proto;
1757100787Sfenner}
1758100787Sfenner
175967682Sobrienvoid
1760163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) {
1761163387Sdwmalone	int l;
1762163387Sdwmalone	int i;
1763163387Sdwmalone
1764163387Sdwmalone	for (i = 0; i < la; i++)
1765163387Sdwmalone		Printf("%02x", (unsigned int)a[i]);
1766163387Sdwmalone	Printf("\n");
1767163387Sdwmalone	l = (la <= lb) ? la : lb;
1768163387Sdwmalone	for (i = 0; i < l; i++)
1769163387Sdwmalone		if (a[i] == b[i])
1770163387Sdwmalone			Printf("__");
1771163387Sdwmalone		else
1772163387Sdwmalone			Printf("%02x", (unsigned int)b[i]);
1773163387Sdwmalone	for (; i < lb; i++)
1774163387Sdwmalone		Printf("%02x", (unsigned int)b[i]);
1775163387Sdwmalone	Printf("\n");
1776163387Sdwmalone}
1777163387Sdwmalone
1778163387Sdwmalone
1779163387Sdwmalonevoid
178018579Sfennerusage(void)
178118579Sfenner{
178218579Sfenner	extern char version[];
178318579Sfenner
178418579Sfenner	Fprintf(stderr, "Version %s\n", version);
1785100787Sfenner	Fprintf(stderr,
1786176428Srpaulo	    "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
1787100787Sfenner	    "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
1788176428Srpaulo	    "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog);
178918579Sfenner	exit(1);
179018579Sfenner}
1791