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$";
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>
222283958Stuexen#include <netinet/sctp.h>
22318579Sfenner#include <netinet/udp.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
248100787Sfenner/* rfc1716 */
249100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB
250100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
251100787Sfenner#endif
252100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE
253100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
254100787Sfenner#endif
255100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
256100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
257100787Sfenner#endif
258100787Sfenner
259100787Sfenner#include "findsaddr.h"
260100787Sfenner#include "ifaddrlist.h"
261176428Srpaulo#include "as.h"
262100787Sfenner#include "traceroute.h"
263100787Sfenner
26418579Sfenner/* Maximum number of gateways (include room for one noop) */
26518579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
26618579Sfenner
26718579Sfenner#ifndef MAXHOSTNAMELEN
26818579Sfenner#define MAXHOSTNAMELEN	64
26918579Sfenner#endif
27018579Sfenner
27118579Sfenner#define Fprintf (void)fprintf
27218579Sfenner#define Printf (void)printf
27318579Sfenner
27446542Sarchie/* What a GRE packet header looks like */
27546542Sarchiestruct grehdr {
27646542Sarchie	u_int16_t   flags;
27746542Sarchie	u_int16_t   proto;
27846542Sarchie	u_int16_t   length;	/* PPTP version of these fields */
27946542Sarchie	u_int16_t   callId;
28046542Sarchie};
28146542Sarchie#ifndef IPPROTO_GRE
28246542Sarchie#define IPPROTO_GRE	47
28346542Sarchie#endif
28446542Sarchie
28546542Sarchie/* For GRE, we prepare what looks like a PPTP packet */
28646542Sarchie#define GRE_PPTP_PROTO	0x880b
28746542Sarchie
288100787Sfenner/* Host name and address list */
289100787Sfennerstruct hostinfo {
290100787Sfenner	char *name;
291100787Sfenner	int n;
292100787Sfenner	u_int32_t *addrs;
293100787Sfenner};
294100787Sfenner
29518579Sfenner/* Data section of the probe packet */
29618579Sfennerstruct outdata {
29718579Sfenner	u_char seq;		/* sequence number of this packet */
29818579Sfenner	u_char ttl;		/* ttl packet left with */
29918579Sfenner	struct timeval tv;	/* time packet left */
30018579Sfenner};
30118579Sfenner
302100787Sfenner#ifndef HAVE_ICMP_NEXTMTU
303100787Sfenner/* Path MTU Discovery (RFC1191) */
304100787Sfennerstruct my_pmtu {
305100787Sfenner	u_short ipm_void;
306100787Sfenner	u_short ipm_nextmtu;
30746542Sarchie};
308100787Sfenner#endif
30946542Sarchie
31018579Sfenneru_char	packet[512];		/* last inbound (icmp) packet */
31118579Sfenner
31246542Sarchiestruct ip *outip;		/* last output ip packet */
313100787Sfenneru_char *outp;		/* last output inner protocol packet */
31418579Sfenner
315163387Sdwmalonestruct ip *hip = NULL;		/* Quoted IP header */
316163387Sdwmaloneint hiplen = 0;
317163387Sdwmalone
31818579Sfenner/* loose source route gateway list (including room for final destination) */
31918579Sfenneru_int32_t gwlist[NGATEWAYS + 1];
32018579Sfenner
32118579Sfennerint s;				/* receive (icmp) socket file descriptor */
32218579Sfennerint sndsock;			/* send (udp) socket file descriptor */
32318579Sfenner
32418579Sfennerstruct sockaddr whereto;	/* Who to try to reach */
325100787Sfennerstruct sockaddr wherefrom;	/* Who we are */
32618579Sfennerint packlen;			/* total length of packet */
32746542Sarchieint protlen;			/* length of protocol part of packet */
328100787Sfennerint minpacket;			/* min ip packet size */
32918579Sfennerint maxpacket = 32 * 1024;	/* max ip packet size */
330100787Sfennerint pmtu;			/* Path MTU Discovery (RFC1191) */
331100787Sfenneru_int pausemsecs;
33218579Sfenner
33318579Sfennerchar *prog;
33418579Sfennerchar *source;
33518579Sfennerchar *hostname;
336100787Sfennerchar *device;
337100787Sfennerstatic const char devnull[] = "/dev/null";
33818579Sfenner
339163387Sdwmaloneint nprobes = -1;
34077816Sruint max_ttl;
341100787Sfennerint first_ttl = 1;
34218579Sfenneru_short ident;
34346542Sarchieu_short port;			/* protocol specific base "port" */
34418579Sfenner
34518579Sfennerint options;			/* socket options */
34618579Sfennerint verbose;
34718579Sfennerint waittime = 5;		/* time to wait for response (in seconds) */
34818579Sfennerint nflag;			/* print addresses numerically */
349176428Srpauloint as_path;			/* print as numbers for each hop */
350176428Srpaulochar *as_server = NULL;
351176428Srpaulovoid *asn;
352100787Sfenner#ifdef CANT_HACK_IPCKSUM
353100787Sfennerint doipcksum = 0;		/* don't calculate ip checksums by default */
354100787Sfenner#else
355100787Sfennerint doipcksum = 1;		/* calculate ip checksums by default */
356100787Sfenner#endif
357100787Sfennerint optlen;			/* length of ip options */
358158424Scjcint fixedPort = 0;		/* Use fixed destination port for TCP and UDP */
359163387Sdwmaloneint printdiff = 0;		/* Print the difference between sent and quoted */
36018579Sfenner
36118579Sfennerextern int optind;
36218579Sfennerextern int opterr;
36318579Sfennerextern char *optarg;
36418579Sfenner
36518579Sfenner/* Forwards */
36618579Sfennerdouble	deltaT(struct timeval *, struct timeval *);
367100787Sfennervoid	freehostinfo(struct hostinfo *);
368100787Sfennervoid	getaddr(u_int32_t *, char *);
369100787Sfennerstruct	hostinfo *gethostinfo(char *);
370100535Sfenneru_short	in_cksum(u_short *, int);
371283958Stuexenu_int32_t sctp_crc32c(const void *, u_int32_t);
37218579Sfennerchar	*inetname(struct in_addr);
37318579Sfennerint	main(int, char **);
374283958Stuexenu_short p_cksum(struct ip *, u_short *, int, int);
37518579Sfennerint	packet_ok(u_char *, int, struct sockaddr_in *, int);
37618579Sfennerchar	*pr_type(u_char);
37718579Sfennervoid	print(u_char *, int, struct sockaddr_in *);
37858804Sshin#ifdef	IPSEC
37958804Sshinint	setpolicy __P((int so, char *policy));
38058804Sshin#endif
38146542Sarchievoid	send_probe(int, int);
382100787Sfennerstruct outproto *setproto(char *);
383100787Sfennerint	str2val(const char *, const char *, int, int);
38418579Sfennervoid	tvsub(struct timeval *, struct timeval *);
38567682Sobrienvoid usage(void);
386100787Sfennerint	wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
387163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int);
388100787Sfenner#ifndef HAVE_USLEEP
389100787Sfennerint	usleep(u_int);
390100787Sfenner#endif
39118579Sfenner
39246542Sarchievoid	udp_prep(struct outdata *);
39346542Sarchieint	udp_check(const u_char *, int);
394283958Stuexenvoid	udplite_prep(struct outdata *);
395283958Stuexenint	udplite_check(const u_char *, int);
39646542Sarchievoid	tcp_prep(struct outdata *);
39746542Sarchieint	tcp_check(const u_char *, int);
398283958Stuexenvoid	sctp_prep(struct outdata *);
399283958Stuexenint	sctp_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	{
433283958Stuexen		"udplite",
434283958Stuexen		"spt dpt cov sum",
435283958Stuexen		IPPROTO_UDPLITE,
436283958Stuexen		sizeof(struct udphdr),
437283958Stuexen		32768 + 666,
438283958Stuexen		udplite_prep,
439283958Stuexen		udplite_check
440283958Stuexen	},
441283958Stuexen	{
44246542Sarchie		"tcp",
443163387Sdwmalone		"spt dpt seq     ack     xxflwin sum urp",
44446542Sarchie		IPPROTO_TCP,
44546542Sarchie		sizeof(struct tcphdr),
44646542Sarchie		32768 + 666,
44746542Sarchie		tcp_prep,
44846542Sarchie		tcp_check
44946542Sarchie	},
45046542Sarchie	{
451283958Stuexen		"sctp",
452283958Stuexen		"spt dpt vtag    crc     tyfllen tyfllen ",
453283958Stuexen		IPPROTO_SCTP,
454283958Stuexen		sizeof(struct sctphdr),
455283958Stuexen		32768 + 666,
456283958Stuexen		sctp_prep,
457283958Stuexen		sctp_check
458283958Stuexen	},
459283958Stuexen	{
46046542Sarchie		"gre",
461163387Sdwmalone		"flg pro len clid",
46246542Sarchie		IPPROTO_GRE,
46346542Sarchie		sizeof(struct grehdr),
46446542Sarchie		GRE_PPTP_PROTO,
46546542Sarchie		gre_prep,
46646542Sarchie		gre_check
46746542Sarchie	},
46846542Sarchie	{
469100535Sfenner		"icmp",
470163387Sdwmalone		"typ cod sum ",
471100535Sfenner		IPPROTO_ICMP,
472100535Sfenner		sizeof(struct icmp),
473100535Sfenner		0,
474100535Sfenner		icmp_prep,
475100535Sfenner		icmp_check
476100535Sfenner	},
477100535Sfenner	{
47846542Sarchie		NULL,
479283958Stuexen		"",
48046542Sarchie		0,
48146542Sarchie		2 * sizeof(u_short),
48246542Sarchie		0,
48346542Sarchie		gen_prep,
48446542Sarchie		gen_check
48546542Sarchie	},
48646542Sarchie};
48746542Sarchiestruct	outproto *proto = &protos[0];
48846542Sarchie
489163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id  off tlprsum srcip   dstip   opts";
490163387Sdwmalone
49118579Sfennerint
49218579Sfennermain(int argc, char **argv)
49318579Sfenner{
494100787Sfenner	register int op, code, n;
49518579Sfenner	register char *cp;
496100787Sfenner	register const char *err;
497100787Sfenner	register u_int32_t *ap;
498100787Sfenner	register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
49918579Sfenner	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
500100787Sfenner	register struct hostinfo *hi;
50118579Sfenner	int on = 1;
50218579Sfenner	register struct protoent *pe;
50318579Sfenner	register int ttl, probe, i;
50418579Sfenner	register int seq = 0;
505100787Sfenner	int tos = 0, settos = 0;
50618579Sfenner	register int lsrr = 0;
507100787Sfenner	register u_short off = 0;
508100787Sfenner	struct ifaddrlist *al;
509100787Sfenner	char errbuf[132];
51048221Sarchie	int requestPort = -1;
51118803Ssef	int sump = 0;
51218583Sfenner	int sockerrno;
51318579Sfenner
514100787Sfenner	/* Insure the socket fds won't be 0, 1 or 2 */
515100787Sfenner	if (open(devnull, O_RDONLY) < 0 ||
516100787Sfenner	    open(devnull, O_RDONLY) < 0 ||
517100787Sfenner	    open(devnull, O_RDONLY) < 0) {
518100787Sfenner		Fprintf(stderr, "%s: open \"%s\": %s\n",
519100787Sfenner		    prog, devnull, strerror(errno));
520100787Sfenner		exit(1);
521100787Sfenner	}
52218583Sfenner	/*
52318583Sfenner	 * Do the setuid-required stuff first, then lose priveleges ASAP.
52418583Sfenner	 * Do error checking for these two calls where they appeared in
52518583Sfenner	 * the original code.
52618583Sfenner	 */
52718583Sfenner	cp = "icmp";
52818583Sfenner	pe = getprotobyname(cp);
52918583Sfenner	if (pe) {
53018583Sfenner		if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
53118583Sfenner			sockerrno = errno;
53218583Sfenner		else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
53318583Sfenner			sockerrno = errno;
53418583Sfenner	}
53518583Sfenner
536220968Ssimon	if (setuid(getuid()) != 0) {
537220968Ssimon		perror("setuid()");
538220968Ssimon		exit(1);
539220968Ssimon	}
54018583Sfenner
54177816Sru#ifdef IPCTL_DEFTTL
54277816Sru	{
54377816Sru		int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
54477816Sru		size_t sz = sizeof(max_ttl);
54577816Sru
546100787Sfenner		if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
547100787Sfenner			perror("sysctl(net.inet.ip.ttl)");
548100787Sfenner			exit(1);
549100787Sfenner		}
55077816Sru	}
55177816Sru#else
55277816Sru	max_ttl = 30;
55377816Sru#endif
55477816Sru
555100787Sfenner	if (argv[0] == NULL)
556100787Sfenner		prog = "traceroute";
557100787Sfenner	else if ((cp = strrchr(argv[0], '/')) != NULL)
55818579Sfenner		prog = cp + 1;
55918579Sfenner	else
56018579Sfenner		prog = argv[0];
56118579Sfenner
56218579Sfenner	opterr = 0;
563176428Srpaulo	while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
56418579Sfenner		switch (op) {
565176428Srpaulo		case 'a':
566176428Srpaulo			as_path = 1;
567176428Srpaulo			break;
568283958Stuexen
569176428Srpaulo		case 'A':
570176428Srpaulo			as_path = 1;
571176428Srpaulo			as_server = optarg;
572176428Srpaulo			break;
573283958Stuexen
57418579Sfenner		case 'd':
57518579Sfenner			options |= SO_DEBUG;
57618579Sfenner			break;
57718579Sfenner
578163387Sdwmalone		case 'D':
579163387Sdwmalone			printdiff = 1;
580163387Sdwmalone			break;
581163387Sdwmalone
582158424Scjc		case 'e':
583158424Scjc			fixedPort = 1;
584158424Scjc			break;
585158424Scjc
586100787Sfenner		case 'f':
587100787Sfenner		case 'M':	/* FreeBSD compat. */
588100787Sfenner			first_ttl = str2val(optarg, "first ttl", 1, 255);
589100787Sfenner			break;
590100787Sfenner
591100787Sfenner		case 'F':
592100787Sfenner			off = IP_DF;
593100787Sfenner			break;
594100787Sfenner
59518579Sfenner		case 'g':
59618579Sfenner			if (lsrr >= NGATEWAYS) {
59718579Sfenner				Fprintf(stderr,
59818579Sfenner				    "%s: No more than %d gateways\n",
59918579Sfenner				    prog, NGATEWAYS);
60018579Sfenner				exit(1);
60118579Sfenner			}
602100787Sfenner			getaddr(gwlist + lsrr, optarg);
60318579Sfenner			++lsrr;
60418579Sfenner			break;
60518579Sfenner
606100787Sfenner		case 'i':
607100787Sfenner			device = optarg;
60847071Sarchie			break;
60947071Sarchie
610100787Sfenner		case 'I':
611100787Sfenner			proto = setproto("icmp");
612100787Sfenner			break;
613100787Sfenner
61418579Sfenner		case 'm':
615100787Sfenner			max_ttl = str2val(optarg, "max ttl", 1, 255);
61618579Sfenner			break;
61718579Sfenner
61818579Sfenner		case 'n':
61918579Sfenner			++nflag;
62018579Sfenner			break;
62118579Sfenner
62246542Sarchie		case 'P':
623100787Sfenner			proto = setproto(optarg);
62446542Sarchie			break;
62546542Sarchie
62618579Sfenner		case 'p':
627100787Sfenner			requestPort = (u_short)str2val(optarg, "port",
628100787Sfenner			    1, (1 << 16) - 1);
62918579Sfenner			break;
63018579Sfenner
63118579Sfenner		case 'q':
632100787Sfenner			nprobes = str2val(optarg, "nprobes", 1, -1);
63318579Sfenner			break;
63418579Sfenner
63518579Sfenner		case 'r':
63618579Sfenner			options |= SO_DONTROUTE;
63718579Sfenner			break;
63818579Sfenner
63918579Sfenner		case 's':
64018579Sfenner			/*
64118579Sfenner			 * set the ip source address of the outbound
64218579Sfenner			 * probe (e.g., on a multi-homed host).
64318579Sfenner			 */
64418579Sfenner			source = optarg;
64518579Sfenner			break;
64618579Sfenner
647100787Sfenner		case 'S':
648100787Sfenner			sump = 1;
649100787Sfenner			break;
650100787Sfenner
65118579Sfenner		case 't':
652100787Sfenner			tos = str2val(optarg, "tos", 0, 255);
653100787Sfenner			++settos;
65418579Sfenner			break;
65518579Sfenner
65618579Sfenner		case 'v':
65718579Sfenner			++verbose;
65818579Sfenner			break;
65918579Sfenner
660100787Sfenner		case 'x':
661100787Sfenner			doipcksum = (doipcksum == 0);
662100787Sfenner			break;
663100787Sfenner
66418579Sfenner		case 'w':
665100787Sfenner			waittime = str2val(optarg, "wait time",
666169144Smaxim			    1, 24 * 60 * 60);
66718579Sfenner			break;
66818579Sfenner
669100787Sfenner		case 'z':
670100787Sfenner			pausemsecs = str2val(optarg, "pause msecs",
671100787Sfenner			    0, 60 * 60 * 1000);
672100787Sfenner			break;
673100787Sfenner
67418579Sfenner		default:
67518579Sfenner			usage();
67618579Sfenner		}
67718579Sfenner
67848221Sarchie	/* Set requested port, if any, else default for this protocol */
67948221Sarchie	port = (requestPort != -1) ? requestPort : proto->port;
68048221Sarchie
681163387Sdwmalone	if (nprobes == -1)
682163387Sdwmalone		nprobes = printdiff ? 1 : 3;
683163387Sdwmalone
684100787Sfenner	if (first_ttl > max_ttl) {
685100787Sfenner		Fprintf(stderr,
686100787Sfenner		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
687100787Sfenner		    prog, first_ttl, max_ttl);
68847071Sarchie		exit(1);
68947071Sarchie	}
69047071Sarchie
691100787Sfenner	if (!doipcksum)
692100787Sfenner		Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
693100787Sfenner
694100787Sfenner	if (lsrr > 0)
695100787Sfenner		optlen = (lsrr + 1) * sizeof(gwlist[0]);
696283958Stuexen	minpacket = sizeof(*outip) + proto->hdrlen + optlen;
697283958Stuexen	if (minpacket > 40)
698283958Stuexen		packlen = minpacket;
699283958Stuexen	else
700283958Stuexen		packlen = 40;
701100787Sfenner
70218579Sfenner	/* Process destination and optional packet size */
70318579Sfenner	switch (argc - optind) {
70418579Sfenner
70518579Sfenner	case 2:
706100787Sfenner		packlen = str2val(argv[optind + 1],
707100787Sfenner		    "packet length", minpacket, maxpacket);
708100787Sfenner		/* Fall through */
70918579Sfenner
71018579Sfenner	case 1:
711100787Sfenner		hostname = argv[optind];
712100787Sfenner		hi = gethostinfo(hostname);
713100787Sfenner		setsin(to, hi->addrs[0]);
714100787Sfenner		if (hi->n > 1)
715100787Sfenner			Fprintf(stderr,
716100787Sfenner		    "%s: Warning: %s has multiple addresses; using %s\n",
717100787Sfenner				prog, hostname, inet_ntoa(to->sin_addr));
718100787Sfenner		hostname = hi->name;
719100787Sfenner		hi->name = NULL;
720100787Sfenner		freehostinfo(hi);
72118579Sfenner		break;
72218579Sfenner
72318579Sfenner	default:
72418579Sfenner		usage();
72518579Sfenner	}
72618579Sfenner
72718579Sfenner#ifdef HAVE_SETLINEBUF
72818579Sfenner	setlinebuf (stdout);
72918579Sfenner#else
73018579Sfenner	setvbuf(stdout, NULL, _IOLBF, 0);
73118579Sfenner#endif
73218579Sfenner
73346542Sarchie	protlen = packlen - sizeof(*outip) - optlen;
734283958Stuexen	if ((proto->num == IPPROTO_SCTP) && (packlen & 3)) {
735283958Stuexen		Fprintf(stderr, "%s: packet length must be a multiple of 4\n",
736283958Stuexen		    prog);
737283958Stuexen		exit(1);
738283958Stuexen	}
73918579Sfenner
74018579Sfenner	outip = (struct ip *)malloc((unsigned)packlen);
74118579Sfenner	if (outip == NULL) {
74218579Sfenner		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
74318579Sfenner		exit(1);
74418579Sfenner	}
74518579Sfenner	memset((char *)outip, 0, packlen);
74618579Sfenner
74718579Sfenner	outip->ip_v = IPVERSION;
748100787Sfenner	if (settos)
749100787Sfenner		outip->ip_tos = tos;
750100787Sfenner#ifdef BYTESWAP_IP_HDR
75118579Sfenner	outip->ip_len = htons(packlen);
752100787Sfenner	outip->ip_off = htons(off);
75318579Sfenner#else
75418579Sfenner	outip->ip_len = packlen;
755100787Sfenner	outip->ip_off = off;
75618579Sfenner#endif
75746542Sarchie	outip->ip_p = proto->num;
758100787Sfenner	outp = (u_char *)(outip + 1);
75918579Sfenner#ifdef HAVE_RAW_OPTIONS
76018579Sfenner	if (lsrr > 0) {
76118579Sfenner		register u_char *optlist;
76218579Sfenner
763100787Sfenner		optlist = outp;
764100787Sfenner		outp += optlen;
76518579Sfenner
76618579Sfenner		/* final hop */
76718579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
76818579Sfenner
76918579Sfenner		outip->ip_dst.s_addr = gwlist[0];
77018579Sfenner
77118579Sfenner		/* force 4 byte alignment */
77218579Sfenner		optlist[0] = IPOPT_NOP;
77318579Sfenner		/* loose source route option */
77418579Sfenner		optlist[1] = IPOPT_LSRR;
77518579Sfenner		i = lsrr * sizeof(gwlist[0]);
77618579Sfenner		optlist[2] = i + 3;
77718579Sfenner		/* Pointer to LSRR addresses */
77818579Sfenner		optlist[3] = IPOPT_MINOFF;
77918579Sfenner		memcpy(optlist + 4, gwlist + 1, i);
78018579Sfenner	} else
78118579Sfenner#endif
78218579Sfenner		outip->ip_dst = to->sin_addr;
78318579Sfenner
784100787Sfenner	outip->ip_hl = (outp - (u_char *)outip) >> 2;
78518579Sfenner	ident = (getpid() & 0xffff) | 0x8000;
78618579Sfenner
78718583Sfenner	if (pe == NULL) {
78818579Sfenner		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
78918579Sfenner		exit(1);
79018579Sfenner	}
79118583Sfenner	if (s < 0) {
79218583Sfenner		errno = sockerrno;
79318579Sfenner		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
79418579Sfenner		exit(1);
79518579Sfenner	}
79618579Sfenner	if (options & SO_DEBUG)
79718579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
79818579Sfenner		    sizeof(on));
79918579Sfenner	if (options & SO_DONTROUTE)
80018579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
80118579Sfenner		    sizeof(on));
80218579Sfenner
80358804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
80458804Sshin	if (setpolicy(s, "in bypass") < 0)
80566809Skris		errx(1, "%s", ipsec_strerror());
80658804Sshin
80758804Sshin	if (setpolicy(s, "out bypass") < 0)
80866809Skris		errx(1, "%s", ipsec_strerror());
80958804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
81058804Sshin
81118583Sfenner	if (sndsock < 0) {
81218583Sfenner		errno = sockerrno;
81318579Sfenner		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
81418579Sfenner		exit(1);
81518579Sfenner	}
81618579Sfenner
81718579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
81818579Sfenner	if (lsrr > 0) {
81918579Sfenner		u_char optlist[MAX_IPOPTLEN];
82018579Sfenner
82118579Sfenner		cp = "ip";
82218579Sfenner		if ((pe = getprotobyname(cp)) == NULL) {
82318579Sfenner			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
82418579Sfenner			exit(1);
82518579Sfenner		}
82618579Sfenner
82718579Sfenner		/* final hop */
82818579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
82918579Sfenner		++lsrr;
83018579Sfenner
83118579Sfenner		/* force 4 byte alignment */
83218579Sfenner		optlist[0] = IPOPT_NOP;
83318579Sfenner		/* loose source route option */
83418579Sfenner		optlist[1] = IPOPT_LSRR;
83518579Sfenner		i = lsrr * sizeof(gwlist[0]);
83618579Sfenner		optlist[2] = i + 3;
83718579Sfenner		/* Pointer to LSRR addresses */
83818579Sfenner		optlist[3] = IPOPT_MINOFF;
83918579Sfenner		memcpy(optlist + 4, gwlist, i);
84018579Sfenner
841100787Sfenner		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
842100787Sfenner		    (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
84318579Sfenner			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
84418579Sfenner			    prog, strerror(errno));
84518579Sfenner			exit(1);
84618579Sfenner		    }
84718579Sfenner	}
84818579Sfenner#endif
84918579Sfenner
85018579Sfenner#ifdef SO_SNDBUF
85118579Sfenner	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
85218579Sfenner	    sizeof(packlen)) < 0) {
85318579Sfenner		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
85418579Sfenner		exit(1);
85518579Sfenner	}
85618579Sfenner#endif
85718579Sfenner#ifdef IP_HDRINCL
85818579Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
85918579Sfenner	    sizeof(on)) < 0) {
86018579Sfenner		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
86118579Sfenner		exit(1);
86218579Sfenner	}
863100787Sfenner#else
864100787Sfenner#ifdef IP_TOS
865100787Sfenner	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
866100787Sfenner	    (char *)&tos, sizeof(tos)) < 0) {
867100787Sfenner		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
868100787Sfenner		    prog, tos, strerror(errno));
869100787Sfenner		exit(1);
870100787Sfenner	}
87118579Sfenner#endif
872100787Sfenner#endif
87318579Sfenner	if (options & SO_DEBUG)
87418579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
87518579Sfenner		    sizeof(on));
87618579Sfenner	if (options & SO_DONTROUTE)
87718579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
87818579Sfenner		    sizeof(on));
87918579Sfenner
880100787Sfenner	/* Get the interface address list */
881100787Sfenner	n = ifaddrlist(&al, errbuf);
882100787Sfenner	if (n < 0) {
883100787Sfenner		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
884100787Sfenner		exit(1);
885100787Sfenner	}
886100787Sfenner	if (n == 0) {
887100787Sfenner		Fprintf(stderr,
888100787Sfenner		    "%s: Can't find any network interfaces\n", prog);
889100787Sfenner		exit(1);
890100787Sfenner	}
891100787Sfenner
892100787Sfenner	/* Look for a specific device */
893100787Sfenner	if (device != NULL) {
894100787Sfenner		for (i = n; i > 0; --i, ++al)
895100787Sfenner			if (strcmp(device, al->device) == 0)
896100787Sfenner				break;
897100787Sfenner		if (i <= 0) {
898100787Sfenner			Fprintf(stderr, "%s: Can't find interface %.32s\n",
899100787Sfenner			    prog, device);
900100787Sfenner			exit(1);
90118579Sfenner		}
90218579Sfenner	}
90318579Sfenner
904100787Sfenner	/* Determine our source address */
905100787Sfenner	if (source == NULL) {
906100787Sfenner		/*
907100787Sfenner		 * If a device was specified, use the interface address.
908100787Sfenner		 * Otherwise, try to determine our source address.
909100787Sfenner		 */
910100787Sfenner		if (device != NULL)
911100787Sfenner			setsin(from, al->addr);
912100787Sfenner		else if ((err = findsaddr(to, from)) != NULL) {
913100787Sfenner			Fprintf(stderr, "%s: findsaddr: %s\n",
914100787Sfenner			    prog, err);
915100787Sfenner			exit(1);
916100787Sfenner		}
917100787Sfenner	} else {
918100787Sfenner		hi = gethostinfo(source);
919100787Sfenner		source = hi->name;
920100787Sfenner		hi->name = NULL;
921100787Sfenner		/*
922100787Sfenner		 * If the device was specified make sure it
923100787Sfenner		 * corresponds to the source address specified.
924100787Sfenner		 * Otherwise, use the first address (and warn if
925100787Sfenner		 * there are more than one).
926100787Sfenner		 */
927100787Sfenner		if (device != NULL) {
928100787Sfenner			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
929100787Sfenner				if (*ap == al->addr)
930100787Sfenner					break;
931100787Sfenner			if (i <= 0) {
932100787Sfenner				Fprintf(stderr,
933100787Sfenner				    "%s: %s is not on interface %.32s\n",
934100787Sfenner				    prog, source, device);
935100787Sfenner				exit(1);
936100787Sfenner			}
937100787Sfenner			setsin(from, *ap);
938100787Sfenner		} else {
939100787Sfenner			setsin(from, hi->addrs[0]);
940100787Sfenner			if (hi->n > 1)
941100787Sfenner				Fprintf(stderr,
942100787Sfenner			"%s: Warning: %s has multiple addresses; using %s\n",
943100787Sfenner				    prog, source, inet_ntoa(from->sin_addr));
944100787Sfenner		}
945100787Sfenner		freehostinfo(hi);
946100787Sfenner	}
947100787Sfenner
948100787Sfenner	outip->ip_src = from->sin_addr;
949128365Spb
950128365Spb	/* Check the source address (-s), if any, is valid */
951100787Sfenner	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
952100787Sfenner		Fprintf(stderr, "%s: bind: %s\n",
953100787Sfenner		    prog, strerror(errno));
954100787Sfenner		exit (1);
955100787Sfenner	}
956100787Sfenner
957176428Srpaulo	if (as_path) {
958176428Srpaulo		asn = as_setup(as_server);
959176428Srpaulo		if (asn == NULL) {
960176428Srpaulo			Fprintf(stderr, "%s: as_setup failed, AS# lookups"
961176428Srpaulo			    " disabled\n", prog);
962176428Srpaulo			(void)fflush(stderr);
963176428Srpaulo			as_path = 0;
964176428Srpaulo		}
965176428Srpaulo	}
966283958Stuexen
96758804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
96858804Sshin	if (setpolicy(sndsock, "in bypass") < 0)
96966809Skris		errx(1, "%s", ipsec_strerror());
97058804Sshin
97158804Sshin	if (setpolicy(sndsock, "out bypass") < 0)
97266809Skris		errx(1, "%s", ipsec_strerror());
97358804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
97458804Sshin
97518579Sfenner	Fprintf(stderr, "%s to %s (%s)",
97618579Sfenner	    prog, hostname, inet_ntoa(to->sin_addr));
97718579Sfenner	if (source)
97818579Sfenner		Fprintf(stderr, " from %s", source);
97918579Sfenner	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
98018579Sfenner	(void)fflush(stderr);
98118579Sfenner
982100787Sfenner	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
98318579Sfenner		u_int32_t lastaddr = 0;
984100787Sfenner		int gotlastaddr = 0;
98518579Sfenner		int got_there = 0;
98618579Sfenner		int unreachable = 0;
987100787Sfenner		int sentfirst = 0;
98818695Ssef		int loss;
98918579Sfenner
99018579Sfenner		Printf("%2d ", ttl);
99118695Ssef		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
99218579Sfenner			register int cc;
99318579Sfenner			struct timeval t1, t2;
99418579Sfenner			register struct ip *ip;
99546542Sarchie			struct outdata outdata;
99618579Sfenner
997100787Sfenner			if (sentfirst && pausemsecs > 0)
998100787Sfenner				usleep(pausemsecs * 1000);
99946542Sarchie			/* Prepare outgoing data */
100046542Sarchie			outdata.seq = ++seq;
100146542Sarchie			outdata.ttl = ttl;
100246542Sarchie
100346542Sarchie			/* Avoid alignment problems by copying bytewise: */
1004211062Sed			(void)gettimeofday(&t1, NULL);
100546542Sarchie			memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
100646542Sarchie
100746542Sarchie			/* Finalize and send packet */
100846542Sarchie			(*proto->prepare)(&outdata);
100946542Sarchie			send_probe(seq, ttl);
1010100787Sfenner			++sentfirst;
101146542Sarchie
101246542Sarchie			/* Wait for a reply */
1013100787Sfenner			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
101418583Sfenner				double T;
101518583Sfenner				int precis;
101618583Sfenner
1017211062Sed				(void)gettimeofday(&t2, NULL);
1018100787Sfenner				i = packet_ok(packet, cc, from, seq);
101918579Sfenner				/* Skip short packet */
102018579Sfenner				if (i == 0)
102118579Sfenner					continue;
1022100787Sfenner				if (!gotlastaddr ||
1023100787Sfenner				    from->sin_addr.s_addr != lastaddr) {
1024154192Spav					if (gotlastaddr) printf("\n   ");
1025100787Sfenner					print(packet, cc, from);
1026100787Sfenner					lastaddr = from->sin_addr.s_addr;
1027100787Sfenner					++gotlastaddr;
102818579Sfenner				}
102918583Sfenner				T = deltaT(&t1, &t2);
103018583Sfenner#ifdef SANE_PRECISION
103118583Sfenner				if (T >= 1000.0)
103218583Sfenner					precis = 0;
103318583Sfenner				else if (T >= 100.0)
103418583Sfenner					precis = 1;
103518583Sfenner				else if (T >= 10.0)
103618583Sfenner					precis = 2;
103718583Sfenner				else
103818583Sfenner#endif
103918583Sfenner					precis = 3;
104018583Sfenner				Printf("  %.*f ms", precis, T);
1041163387Sdwmalone				if (printdiff) {
1042163387Sdwmalone					Printf("\n");
1043163387Sdwmalone					Printf("%*.*s%s\n",
1044163387Sdwmalone					    -(outip->ip_hl << 3),
1045163387Sdwmalone					    outip->ip_hl << 3,
1046163387Sdwmalone					    ip_hdr_key,
1047163387Sdwmalone					    proto->key);
1048163387Sdwmalone					pkt_compare((void *)outip, packlen,
1049163387Sdwmalone					    (void *)hip, hiplen);
1050163387Sdwmalone				}
1051100535Sfenner				if (i == -2) {
1052100567Sdcs#ifndef ARCHAIC
1053100535Sfenner					ip = (struct ip *)packet;
1054100535Sfenner					if (ip->ip_ttl <= 1)
1055100535Sfenner						Printf(" !");
1056100535Sfenner#endif
1057100535Sfenner					++got_there;
1058100535Sfenner					break;
1059100535Sfenner				}
106018579Sfenner				/* time exceeded in transit */
106118579Sfenner				if (i == -1)
106218579Sfenner					break;
106318579Sfenner				code = i - 1;
106418579Sfenner				switch (code) {
106518579Sfenner
106618579Sfenner				case ICMP_UNREACH_PORT:
106718579Sfenner#ifndef ARCHAIC
106818579Sfenner					ip = (struct ip *)packet;
106918579Sfenner					if (ip->ip_ttl <= 1)
107018579Sfenner						Printf(" !");
107118579Sfenner#endif
107218579Sfenner					++got_there;
107318579Sfenner					break;
107418579Sfenner
107518579Sfenner				case ICMP_UNREACH_NET:
107618579Sfenner					++unreachable;
107718579Sfenner					Printf(" !N");
107818579Sfenner					break;
107918579Sfenner
108018579Sfenner				case ICMP_UNREACH_HOST:
108118579Sfenner					++unreachable;
108218579Sfenner					Printf(" !H");
108318579Sfenner					break;
108418579Sfenner
108518579Sfenner				case ICMP_UNREACH_PROTOCOL:
108618579Sfenner					++got_there;
108718579Sfenner					Printf(" !P");
108818579Sfenner					break;
108918579Sfenner
109018579Sfenner				case ICMP_UNREACH_NEEDFRAG:
109118579Sfenner					++unreachable;
1092100787Sfenner					Printf(" !F-%d", pmtu);
109318579Sfenner					break;
109418579Sfenner
109518579Sfenner				case ICMP_UNREACH_SRCFAIL:
109618579Sfenner					++unreachable;
109718579Sfenner					Printf(" !S");
109818579Sfenner					break;
109918579Sfenner
1100159576Sdwmalone				case ICMP_UNREACH_NET_UNKNOWN:
1101159576Sdwmalone					++unreachable;
1102159576Sdwmalone					Printf(" !U");
1103159576Sdwmalone					break;
1104159576Sdwmalone
1105159576Sdwmalone				case ICMP_UNREACH_HOST_UNKNOWN:
1106159576Sdwmalone					++unreachable;
1107159576Sdwmalone					Printf(" !W");
1108159576Sdwmalone					break;
1109159576Sdwmalone
1110159576Sdwmalone				case ICMP_UNREACH_ISOLATED:
1111159576Sdwmalone					++unreachable;
1112159576Sdwmalone					Printf(" !I");
1113159576Sdwmalone					break;
1114159576Sdwmalone
1115159576Sdwmalone				case ICMP_UNREACH_NET_PROHIB:
1116159576Sdwmalone					++unreachable;
1117159576Sdwmalone					Printf(" !A");
1118159576Sdwmalone					break;
1119159576Sdwmalone
1120159576Sdwmalone				case ICMP_UNREACH_HOST_PROHIB:
1121159576Sdwmalone					++unreachable;
1122159576Sdwmalone					Printf(" !Z");
1123159576Sdwmalone					break;
1124159576Sdwmalone
1125159576Sdwmalone				case ICMP_UNREACH_TOSNET:
1126159576Sdwmalone					++unreachable;
1127159576Sdwmalone					Printf(" !Q");
1128159576Sdwmalone					break;
1129159576Sdwmalone
1130159576Sdwmalone				case ICMP_UNREACH_TOSHOST:
1131159576Sdwmalone					++unreachable;
1132159576Sdwmalone					Printf(" !T");
1133159576Sdwmalone					break;
1134159576Sdwmalone
113518579Sfenner				case ICMP_UNREACH_FILTER_PROHIB:
113618579Sfenner					++unreachable;
113718579Sfenner					Printf(" !X");
113818579Sfenner					break;
113918579Sfenner
1140100787Sfenner				case ICMP_UNREACH_HOST_PRECEDENCE:
1141100787Sfenner					++unreachable;
1142100787Sfenner					Printf(" !V");
1143100787Sfenner					break;
1144100787Sfenner
1145100787Sfenner				case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1146100787Sfenner					++unreachable;
1147100787Sfenner					Printf(" !C");
1148100787Sfenner					break;
1149100787Sfenner
115018579Sfenner				default:
115118579Sfenner					++unreachable;
115218579Sfenner					Printf(" !<%d>", code);
115318579Sfenner					break;
115418579Sfenner				}
115518579Sfenner				break;
115618579Sfenner			}
115718695Ssef			if (cc == 0) {
115818695Ssef				loss++;
115918579Sfenner				Printf(" *");
116018695Ssef			}
116118579Sfenner			(void)fflush(stdout);
116218579Sfenner		}
116318803Ssef		if (sump) {
116418811Ssef			Printf(" (%d%% loss)", (loss * 100) / nprobes);
116518803Ssef		}
116618579Sfenner		putchar('\n');
116718579Sfenner		if (got_there ||
116818579Sfenner		    (unreachable > 0 && unreachable >= nprobes - 1))
116918579Sfenner			break;
117018579Sfenner	}
1171176428Srpaulo	if (as_path)
1172176428Srpaulo		as_shutdown(asn);
117318579Sfenner	exit(0);
117418579Sfenner}
117518579Sfenner
117618579Sfennerint
117718579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp,
1178100787Sfenner    register const struct timeval *tp)
117918579Sfenner{
118066810Skris	fd_set *fdsp;
118166810Skris	size_t nfds;
118218579Sfenner	struct timeval now, wait;
118318579Sfenner	register int cc = 0;
118444086Sdes	register int error;
118518579Sfenner	int fromlen = sizeof(*fromp);
118618579Sfenner
118766810Skris	nfds = howmany(sock + 1, NFDBITS);
118898709Srobert	if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
118966810Skris		err(1, "malloc");
119098709Srobert	memset(fdsp, 0, nfds * sizeof(fd_mask));
119166810Skris	FD_SET(sock, fdsp);
119218579Sfenner
119318579Sfenner	wait.tv_sec = tp->tv_sec + waittime;
119418579Sfenner	wait.tv_usec = tp->tv_usec;
1195211062Sed	(void)gettimeofday(&now, NULL);
119618579Sfenner	tvsub(&wait, &now);
119744086Sdes	if (wait.tv_sec < 0) {
119844086Sdes		wait.tv_sec = 0;
119944086Sdes		wait.tv_usec = 1;
120044086Sdes	}
120118579Sfenner
120266810Skris	error = select(sock + 1, fdsp, NULL, NULL, &wait);
120344086Sdes	if (error == -1 && errno == EINVAL) {
120444086Sdes		Fprintf(stderr, "%s: botched select() args\n", prog);
120544086Sdes		exit(1);
120644086Sdes	}
120744086Sdes	if (error > 0)
1208100787Sfenner		cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
120918579Sfenner			    (struct sockaddr *)fromp, &fromlen);
121018579Sfenner
121166810Skris	free(fdsp);
121218579Sfenner	return(cc);
121318579Sfenner}
121418579Sfenner
1215100787Sfennervoid
1216100787Sfennersend_probe(int seq, int ttl)
1217100787Sfenner{
1218100787Sfenner	register int cc;
1219100787Sfenner
1220100787Sfenner	outip->ip_ttl = ttl;
1221100787Sfenner	outip->ip_id = htons(ident + seq);
1222100787Sfenner
1223100787Sfenner	/* XXX undocumented debugging hack */
1224100787Sfenner	if (verbose > 1) {
1225100787Sfenner		register const u_short *sp;
1226100787Sfenner		register int nshorts, i;
1227100787Sfenner
1228100787Sfenner		sp = (u_short *)outip;
1229100787Sfenner		nshorts = (u_int)packlen / sizeof(u_short);
1230100787Sfenner		i = 0;
1231100787Sfenner		Printf("[ %d bytes", packlen);
1232100787Sfenner		while (--nshorts >= 0) {
1233100787Sfenner			if ((i++ % 8) == 0)
1234100787Sfenner				Printf("\n\t");
1235100787Sfenner			Printf(" %04x", ntohs(*sp++));
1236100787Sfenner		}
1237100787Sfenner		if (packlen & 1) {
1238100787Sfenner			if ((i % 8) == 0)
1239100787Sfenner				Printf("\n\t");
1240100787Sfenner			Printf(" %02x", *(u_char *)sp);
1241100787Sfenner		}
1242100787Sfenner		Printf("]\n");
1243100787Sfenner	}
1244100787Sfenner
1245100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL)
1246100787Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1247100787Sfenner	    (char *)&ttl, sizeof(ttl)) < 0) {
1248100787Sfenner		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1249100787Sfenner		    prog, ttl, strerror(errno));
1250100787Sfenner		exit(1);
1251100787Sfenner	}
1252100787Sfenner#endif
1253100787Sfenner
1254100787Sfenner	cc = sendto(sndsock, (char *)outip,
1255100787Sfenner	    packlen, 0, &whereto, sizeof(whereto));
1256100787Sfenner	if (cc < 0 || cc != packlen)  {
1257100787Sfenner		if (cc < 0)
1258100787Sfenner			Fprintf(stderr, "%s: sendto: %s\n",
1259100787Sfenner			    prog, strerror(errno));
1260100787Sfenner		Printf("%s: wrote %s %d chars, ret=%d\n",
1261100787Sfenner		    prog, hostname, packlen, cc);
1262100787Sfenner		(void)fflush(stdout);
1263100787Sfenner	}
1264100787Sfenner}
1265100787Sfenner
126658804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
126758804Sshinint
126858804Sshinsetpolicy(so, policy)
126958804Sshin	int so;
127058804Sshin	char *policy;
127158804Sshin{
127258804Sshin	char *buf;
127358804Sshin
127458804Sshin	buf = ipsec_set_policy(policy, strlen(policy));
127558804Sshin	if (buf == NULL) {
127666809Skris		warnx("%s", ipsec_strerror());
127758804Sshin		return -1;
127858804Sshin	}
127958804Sshin	(void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
128058804Sshin		buf, ipsec_get_policylen(buf));
128158804Sshin
128258804Sshin	free(buf);
128358804Sshin
128458804Sshin	return 0;
128558804Sshin}
128658804Sshin#endif
128758804Sshin
128818579Sfennerdouble
128918579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p)
129018579Sfenner{
129118579Sfenner	register double dt;
129218579Sfenner
129318579Sfenner	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
129418579Sfenner	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
129518579Sfenner	return (dt);
129618579Sfenner}
129718579Sfenner
129818579Sfenner/*
129918579Sfenner * Convert an ICMP "type" field to a printable string.
130018579Sfenner */
130118579Sfennerchar *
130218579Sfennerpr_type(register u_char t)
130318579Sfenner{
130418579Sfenner	static char *ttab[] = {
130518579Sfenner	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
130618579Sfenner	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
130718579Sfenner	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
130818579Sfenner	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
130918579Sfenner	"Info Reply"
131018579Sfenner	};
131118579Sfenner
131218579Sfenner	if (t > 16)
131318579Sfenner		return("OUT-OF-RANGE");
131418579Sfenner
131518579Sfenner	return(ttab[t]);
131618579Sfenner}
131718579Sfenner
131818579Sfennerint
131918579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
132018579Sfenner    register int seq)
132118579Sfenner{
132218579Sfenner	register struct icmp *icp;
132318579Sfenner	register u_char type, code;
132418579Sfenner	register int hlen;
132518579Sfenner#ifndef ARCHAIC
132618579Sfenner	register struct ip *ip;
132718579Sfenner
132818579Sfenner	ip = (struct ip *) buf;
132918579Sfenner	hlen = ip->ip_hl << 2;
133018579Sfenner	if (cc < hlen + ICMP_MINLEN) {
133118579Sfenner		if (verbose)
133218579Sfenner			Printf("packet too short (%d bytes) from %s\n", cc,
133318579Sfenner				inet_ntoa(from->sin_addr));
133418579Sfenner		return (0);
133518579Sfenner	}
133618579Sfenner	cc -= hlen;
133718579Sfenner	icp = (struct icmp *)(buf + hlen);
133818579Sfenner#else
133918579Sfenner	icp = (struct icmp *)buf;
134018579Sfenner#endif
134118579Sfenner	type = icp->icmp_type;
134218579Sfenner	code = icp->icmp_code;
1343100787Sfenner	/* Path MTU Discovery (RFC1191) */
1344100787Sfenner	if (code != ICMP_UNREACH_NEEDFRAG)
1345100787Sfenner		pmtu = 0;
1346100787Sfenner	else {
1347100787Sfenner#ifdef HAVE_ICMP_NEXTMTU
1348100787Sfenner		pmtu = ntohs(icp->icmp_nextmtu);
1349100787Sfenner#else
1350100787Sfenner		pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1351100787Sfenner#endif
1352100787Sfenner	}
1353100535Sfenner	if (type == ICMP_ECHOREPLY
1354100535Sfenner	    && proto->num == IPPROTO_ICMP
1355124859Scperciva	    && (*proto->check)((u_char *)icp, (u_char)seq))
1356100535Sfenner		return -2;
135718579Sfenner	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
135818579Sfenner	    type == ICMP_UNREACH) {
135946542Sarchie		u_char *inner;
136018579Sfenner
136118579Sfenner		hip = &icp->icmp_ip;
1362163387Sdwmalone		hiplen = ((u_char *)icp + cc) - (u_char *)hip;
136318579Sfenner		hlen = hip->ip_hl << 2;
136446542Sarchie		inner = (u_char *)((u_char *)hip + hlen);
1365283958Stuexen		if (hlen + 16 <= cc
136646542Sarchie		    && hip->ip_p == proto->num
1367124859Scperciva		    && (*proto->check)(inner, (u_char)seq))
136818579Sfenner			return (type == ICMP_TIMXCEED ? -1 : code + 1);
136918579Sfenner	}
137018579Sfenner#ifndef ARCHAIC
137118579Sfenner	if (verbose) {
137218579Sfenner		register int i;
137318579Sfenner		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
137418579Sfenner
137518579Sfenner		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
137618579Sfenner		Printf("%s: icmp type %d (%s) code %d\n",
137718579Sfenner		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1378283958Stuexen		for (i = 4; i <= cc - ICMP_MINLEN; i += sizeof(*lp))
1379283958Stuexen			Printf("%2d: %8.8x\n", i, ntohl(*lp++));
138018579Sfenner	}
138118579Sfenner#endif
138218579Sfenner	return(0);
138318579Sfenner}
138418579Sfenner
138546542Sarchievoid
1386100535Sfennericmp_prep(struct outdata *outdata)
1387100535Sfenner{
1388100787Sfenner	struct icmp *const icmpheader = (struct icmp *) outp;
1389100535Sfenner
1390100535Sfenner	icmpheader->icmp_type = ICMP_ECHO;
1391100535Sfenner	icmpheader->icmp_id = htons(ident);
1392100535Sfenner	icmpheader->icmp_seq = htons(outdata->seq);
1393100535Sfenner	icmpheader->icmp_cksum = 0;
1394100789Sfenner	icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
1395100535Sfenner	if (icmpheader->icmp_cksum == 0)
1396100535Sfenner		icmpheader->icmp_cksum = 0xffff;
1397100535Sfenner}
1398100535Sfenner
1399100535Sfennerint
1400100535Sfennericmp_check(const u_char *data, int seq)
1401100535Sfenner{
1402100535Sfenner	struct icmp *const icmpheader = (struct icmp *) data;
1403100535Sfenner
1404100535Sfenner	return (icmpheader->icmp_id == htons(ident)
1405100535Sfenner	    && icmpheader->icmp_seq == htons(seq));
1406100535Sfenner}
1407100535Sfenner
1408100535Sfennervoid
140946542Sarchieudp_prep(struct outdata *outdata)
141046542Sarchie{
1411100787Sfenner	struct udphdr *const outudp = (struct udphdr *) outp;
141218579Sfenner
1413158424Scjc	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1414158424Scjc	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1415100787Sfenner	outudp->uh_ulen = htons((u_short)protlen);
1416100789Sfenner	outudp->uh_sum = 0;
1417100787Sfenner	if (doipcksum) {
1418283958Stuexen	    u_short sum = p_cksum(outip, (u_short*)outudp, protlen, protlen);
1419100789Sfenner	    outudp->uh_sum = (sum) ? sum : 0xffff;
1420100787Sfenner	}
1421100789Sfenner
1422100789Sfenner	return;
142346542Sarchie}
142446542Sarchie
142546542Sarchieint
142646542Sarchieudp_check(const u_char *data, int seq)
142746542Sarchie{
142846542Sarchie	struct udphdr *const udp = (struct udphdr *) data;
142946542Sarchie
1430158424Scjc	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1431158424Scjc	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
143246542Sarchie}
143346542Sarchie
143418579Sfennervoid
1435283958Stuexenudplite_prep(struct outdata *outdata)
1436283958Stuexen{
1437283958Stuexen	struct udphdr *const outudp = (struct udphdr *) outp;
1438283958Stuexen
1439283958Stuexen	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1440283958Stuexen	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1441283958Stuexen	outudp->uh_ulen = htons(8);
1442283958Stuexen	outudp->uh_sum = 0;
1443283958Stuexen	if (doipcksum) {
1444283958Stuexen	    u_short sum = p_cksum(outip, (u_short*)outudp, protlen, 8);
1445283958Stuexen	    outudp->uh_sum = (sum) ? sum : 0xffff;
1446283958Stuexen	}
1447283958Stuexen
1448283958Stuexen	return;
1449283958Stuexen}
1450283958Stuexen
1451283958Stuexenint
1452283958Stuexenudplite_check(const u_char *data, int seq)
1453283958Stuexen{
1454283958Stuexen	struct udphdr *const udp = (struct udphdr *) data;
1455283958Stuexen
1456283958Stuexen	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1457283958Stuexen	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
1458283958Stuexen}
1459283958Stuexen
1460283958Stuexenvoid
146146542Sarchietcp_prep(struct outdata *outdata)
146246542Sarchie{
1463100787Sfenner	struct tcphdr *const tcp = (struct tcphdr *) outp;
146446542Sarchie
146546542Sarchie	tcp->th_sport = htons(ident);
1466158424Scjc	tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1467234701Stuexen	tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
146846542Sarchie	tcp->th_ack = 0;
146946542Sarchie	tcp->th_off = 5;
147046542Sarchie	tcp->th_flags = TH_SYN;
1471100789Sfenner	tcp->th_sum = 0;
1472100789Sfenner
1473283958Stuexen	if (doipcksum)
1474283958Stuexen	    tcp->th_sum = p_cksum(outip, (u_short*)tcp, protlen, protlen);
147546542Sarchie}
147646542Sarchie
147746542Sarchieint
147846542Sarchietcp_check(const u_char *data, int seq)
147946542Sarchie{
148046542Sarchie	struct tcphdr *const tcp = (struct tcphdr *) data;
148146542Sarchie
148246542Sarchie	return (ntohs(tcp->th_sport) == ident
1483234701Stuexen	    && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq)
1484234701Stuexen	    && tcp->th_seq == (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport));
148546542Sarchie}
148646542Sarchie
148746542Sarchievoid
1488283958Stuexensctp_prep(struct outdata *outdata)
1489283958Stuexen{
1490283958Stuexen	struct sctphdr *const sctp = (struct sctphdr *) outp;
1491283958Stuexen	struct sctp_chunkhdr *chk;
1492283958Stuexen
1493283958Stuexen	sctp->src_port = htons(ident);
1494283958Stuexen	sctp->dest_port = htons(port + (fixedPort ? 0 : outdata->seq));
1495283958Stuexen	sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
1496283958Stuexen	sctp->checksum = htonl(0);
1497283958Stuexen	if (protlen >=
1498283958Stuexen	    (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) {
1499283958Stuexen		chk = (struct sctp_chunkhdr *)(sctp + 1);
1500283958Stuexen		chk->chunk_type = SCTP_SHUTDOWN_ACK;
1501283958Stuexen		chk->chunk_flags = 0;
1502283958Stuexen		chk->chunk_length = htons(4);
1503283958Stuexen	}
1504283958Stuexen	if (protlen >=
1505283958Stuexen	    (int)(sizeof(struct sctphdr) + 2 * sizeof(struct sctp_chunkhdr))) {
1506283958Stuexen		chk = chk + 1;
1507283958Stuexen		chk->chunk_type = SCTP_PAD_CHUNK;
1508283958Stuexen		chk->chunk_flags = 0;
1509283958Stuexen		chk->chunk_length = htons(protlen -
1510283958Stuexen		    (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
1511283958Stuexen	}
1512283958Stuexen	if (doipcksum) {
1513283958Stuexen		sctp->checksum = sctp_crc32c(sctp, protlen);
1514283958Stuexen	}
1515283958Stuexen}
1516283958Stuexen
1517283958Stuexenint
1518283958Stuexensctp_check(const u_char *data, int seq)
1519283958Stuexen{
1520283958Stuexen	struct sctphdr *const sctp = (struct sctphdr *) data;
1521283958Stuexen
1522283958Stuexen	return (ntohs(sctp->src_port) == ident
1523283958Stuexen	    && ntohs(sctp->dest_port) == port + (fixedPort ? 0 : seq)
1524283958Stuexen	    && sctp->v_tag ==
1525283958Stuexen	    (u_int32_t)((sctp->src_port << 16) | sctp->dest_port));
1526283958Stuexen}
1527283958Stuexen
1528283958Stuexenvoid
152946542Sarchiegre_prep(struct outdata *outdata)
153046542Sarchie{
1531100787Sfenner	struct grehdr *const gre = (struct grehdr *) outp;
153246542Sarchie
153346542Sarchie	gre->flags = htons(0x2001);
153446542Sarchie	gre->proto = htons(port);
153546542Sarchie	gre->length = 0;
153646542Sarchie	gre->callId = htons(ident + outdata->seq);
153746542Sarchie}
153846542Sarchie
153946542Sarchieint
154046542Sarchiegre_check(const u_char *data, int seq)
154146542Sarchie{
154246542Sarchie	struct grehdr *const gre = (struct grehdr *) data;
154346542Sarchie
154446542Sarchie	return(ntohs(gre->proto) == port
154546542Sarchie	    && ntohs(gre->callId) == ident + seq);
154646542Sarchie}
154746542Sarchie
154846542Sarchievoid
154946542Sarchiegen_prep(struct outdata *outdata)
155046542Sarchie{
1551100787Sfenner	u_int16_t *const ptr = (u_int16_t *) outp;
155246542Sarchie
155346542Sarchie	ptr[0] = htons(ident);
155446542Sarchie	ptr[1] = htons(port + outdata->seq);
155546542Sarchie}
155646542Sarchie
155746542Sarchieint
155846542Sarchiegen_check(const u_char *data, int seq)
155946542Sarchie{
156046542Sarchie	u_int16_t *const ptr = (u_int16_t *) data;
156146542Sarchie
156246542Sarchie	return(ntohs(ptr[0]) == ident
156346542Sarchie	    && ntohs(ptr[1]) == port + seq);
156446542Sarchie}
156546542Sarchie
156646542Sarchievoid
156718579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from)
156818579Sfenner{
156918579Sfenner	register struct ip *ip;
157018579Sfenner	register int hlen;
1571196475Sume	char addr[INET_ADDRSTRLEN];
157218579Sfenner
157318579Sfenner	ip = (struct ip *) buf;
157418579Sfenner	hlen = ip->ip_hl << 2;
157518579Sfenner	cc -= hlen;
157618579Sfenner
1577196475Sume	strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
1578196475Sume
1579176428Srpaulo	if (as_path)
1580196475Sume		Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
1581176428Srpaulo
158218579Sfenner	if (nflag)
1583196475Sume		Printf(" %s", addr);
158418579Sfenner	else
1585196475Sume		Printf(" %s (%s)", inetname(from->sin_addr), addr);
158618579Sfenner
158718579Sfenner	if (verbose)
158818579Sfenner		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
158918579Sfenner}
159018579Sfenner
159118579Sfenner/*
1592100789Sfenner * Checksum routine for UDP and TCP headers.
1593100789Sfenner */
1594283958Stuexenu_short
1595283958Stuexenp_cksum(struct ip *ip, u_short *data, int len, int cov)
1596100789Sfenner{
1597100789Sfenner	static struct ipovly ipo;
1598216184Suqs	u_short sum[2];
1599100789Sfenner
1600100789Sfenner	ipo.ih_pr = ip->ip_p;
1601100789Sfenner	ipo.ih_len = htons(len);
1602100789Sfenner	ipo.ih_src = ip->ip_src;
1603100789Sfenner	ipo.ih_dst = ip->ip_dst;
1604100789Sfenner
1605216184Suqs	sum[1] = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
1606283958Stuexen	sum[0] = in_cksum(data, cov);                   /* payload data cksum */
1607100789Sfenner
1608216184Suqs	return ~in_cksum(sum, sizeof(sum));
1609100789Sfenner}
1610100789Sfenner
1611100789Sfenner/*
161218579Sfenner * Checksum routine for Internet Protocol family headers (C Version)
161318579Sfenner */
1614100535Sfenneru_short
161518579Sfennerin_cksum(register u_short *addr, register int len)
161618579Sfenner{
161718579Sfenner	register int nleft = len;
161818579Sfenner	register u_short *w = addr;
161918579Sfenner	register u_short answer;
162018579Sfenner	register int sum = 0;
162118579Sfenner
162218579Sfenner	/*
162318579Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
162418579Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
162518579Sfenner	 *  back all the carry bits from the top 16 bits into the lower
162618579Sfenner	 *  16 bits.
162718579Sfenner	 */
162818579Sfenner	while (nleft > 1)  {
162918579Sfenner		sum += *w++;
163018579Sfenner		nleft -= 2;
163118579Sfenner	}
163218579Sfenner
163318579Sfenner	/* mop up an odd byte, if necessary */
163418579Sfenner	if (nleft == 1)
163518579Sfenner		sum += *(u_char *)w;
163618579Sfenner
163718579Sfenner	/*
163818579Sfenner	 * add back carry outs from top 16 bits to low 16 bits
163918579Sfenner	 */
164018579Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
164118579Sfenner	sum += (sum >> 16);			/* add carry */
164218579Sfenner	answer = ~sum;				/* truncate to 16 bits */
164318579Sfenner	return (answer);
164418579Sfenner}
164518579Sfenner
164618579Sfenner/*
1647283958Stuexen * CRC32C routine for the Stream Control Transmission Protocol
1648283958Stuexen */
1649283958Stuexen
1650283958Stuexen#define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
1651283958Stuexen
1652283958Stuexenstatic u_int32_t crc_c[256] = {
1653283958Stuexen	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
1654283958Stuexen	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
1655283958Stuexen	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
1656283958Stuexen	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
1657283958Stuexen	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
1658283958Stuexen	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
1659283958Stuexen	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
1660283958Stuexen	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
1661283958Stuexen	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
1662283958Stuexen	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
1663283958Stuexen	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
1664283958Stuexen	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
1665283958Stuexen	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
1666283958Stuexen	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
1667283958Stuexen	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
1668283958Stuexen	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
1669283958Stuexen	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
1670283958Stuexen	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
1671283958Stuexen	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
1672283958Stuexen	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
1673283958Stuexen	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
1674283958Stuexen	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
1675283958Stuexen	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
1676283958Stuexen	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
1677283958Stuexen	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
1678283958Stuexen	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
1679283958Stuexen	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
1680283958Stuexen	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
1681283958Stuexen	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
1682283958Stuexen	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
1683283958Stuexen	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
1684283958Stuexen	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
1685283958Stuexen	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
1686283958Stuexen	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
1687283958Stuexen	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
1688283958Stuexen	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
1689283958Stuexen	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
1690283958Stuexen	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
1691283958Stuexen	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
1692283958Stuexen	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
1693283958Stuexen	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
1694283958Stuexen	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
1695283958Stuexen	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
1696283958Stuexen	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
1697283958Stuexen	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
1698283958Stuexen	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
1699283958Stuexen	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
1700283958Stuexen	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
1701283958Stuexen	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
1702283958Stuexen	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
1703283958Stuexen	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
1704283958Stuexen	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
1705283958Stuexen	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
1706283958Stuexen	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
1707283958Stuexen	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
1708283958Stuexen	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
1709283958Stuexen	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
1710283958Stuexen	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
1711283958Stuexen	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
1712283958Stuexen	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
1713283958Stuexen	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
1714283958Stuexen	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
1715283958Stuexen	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
1716283958Stuexen	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
1717283958Stuexen};
1718283958Stuexen
1719283958Stuexenu_int32_t
1720283958Stuexensctp_crc32c(const void *packet, u_int32_t len)
1721283958Stuexen{
1722283958Stuexen	u_int32_t i, crc32c;
1723283958Stuexen	u_int8_t byte0, byte1, byte2, byte3;
1724283958Stuexen	const u_int8_t *buf = (const u_int8_t *)packet;
1725283958Stuexen
1726283958Stuexen	crc32c = ~0;
1727283958Stuexen	for (i = 0; i < len; i++)
1728283958Stuexen		CRC32C(crc32c, buf[i]);
1729283958Stuexen	crc32c = ~crc32c;
1730283958Stuexen	byte0  = crc32c & 0xff;
1731283958Stuexen	byte1  = (crc32c>>8) & 0xff;
1732283958Stuexen	byte2  = (crc32c>>16) & 0xff;
1733283958Stuexen	byte3  = (crc32c>>24) & 0xff;
1734283958Stuexen	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
1735283958Stuexen	return htonl(crc32c);
1736283958Stuexen}
1737283958Stuexen
1738283958Stuexen/*
173918579Sfenner * Subtract 2 timeval structs:  out = out - in.
174044086Sdes * Out is assumed to be within about LONG_MAX seconds of in.
174118579Sfenner */
174218579Sfennervoid
174318579Sfennertvsub(register struct timeval *out, register struct timeval *in)
174418579Sfenner{
174518579Sfenner
174618579Sfenner	if ((out->tv_usec -= in->tv_usec) < 0)   {
174718579Sfenner		--out->tv_sec;
174818579Sfenner		out->tv_usec += 1000000;
174918579Sfenner	}
175018579Sfenner	out->tv_sec -= in->tv_sec;
175118579Sfenner}
175218579Sfenner
175318579Sfenner/*
175418579Sfenner * Construct an Internet address representation.
175518579Sfenner * If the nflag has been supplied, give
175618579Sfenner * numeric value, otherwise try for symbolic name.
175718579Sfenner */
175818579Sfennerchar *
175918579Sfennerinetname(struct in_addr in)
176018579Sfenner{
176118579Sfenner	register char *cp;
176218579Sfenner	register struct hostent *hp;
176318579Sfenner	static int first = 1;
176418579Sfenner	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
176518579Sfenner
176618579Sfenner	if (first && !nflag) {
176718579Sfenner		first = 0;
1768100787Sfenner		if (gethostname(domain, sizeof(domain) - 1) < 0)
176918579Sfenner			domain[0] = '\0';
1770100787Sfenner		else {
1771100787Sfenner			cp = strchr(domain, '.');
1772100787Sfenner			if (cp == NULL) {
1773100787Sfenner				hp = gethostbyname(domain);
1774100787Sfenner				if (hp != NULL)
1775100787Sfenner					cp = strchr(hp->h_name, '.');
1776100787Sfenner			}
1777100787Sfenner			if (cp == NULL)
1778100787Sfenner				domain[0] = '\0';
1779100787Sfenner			else {
1780100787Sfenner				++cp;
1781100787Sfenner				(void)strncpy(domain, cp, sizeof(domain) - 1);
1782100787Sfenner				domain[sizeof(domain) - 1] = '\0';
1783100787Sfenner			}
1784100787Sfenner		}
178518579Sfenner	}
178618579Sfenner	if (!nflag && in.s_addr != INADDR_ANY) {
178718579Sfenner		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
178818579Sfenner		if (hp != NULL) {
178918579Sfenner			if ((cp = strchr(hp->h_name, '.')) != NULL &&
179018579Sfenner			    strcmp(cp + 1, domain) == 0)
179118579Sfenner				*cp = '\0';
179218579Sfenner			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
179318579Sfenner			line[sizeof(line) - 1] = '\0';
179418579Sfenner			return (line);
179518579Sfenner		}
179618579Sfenner	}
179718579Sfenner	return (inet_ntoa(in));
179818579Sfenner}
179918579Sfenner
1800100787Sfennerstruct hostinfo *
1801100787Sfennergethostinfo(register char *hostname)
180218579Sfenner{
1803100787Sfenner	register int n;
180418579Sfenner	register struct hostent *hp;
1805100787Sfenner	register struct hostinfo *hi;
1806100787Sfenner	register char **p;
1807100787Sfenner	register u_int32_t addr, *ap;
180818579Sfenner
1809223579Sdim	if (strlen(hostname) >= MAXHOSTNAMELEN) {
1810100787Sfenner		Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1811100787Sfenner		    prog, hostname);
1812100787Sfenner		exit(1);
1813100787Sfenner	}
1814100787Sfenner	hi = calloc(1, sizeof(*hi));
1815100787Sfenner	if (hi == NULL) {
1816100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1817100787Sfenner		exit(1);
1818100787Sfenner	}
1819100787Sfenner	addr = inet_addr(hostname);
1820100787Sfenner	if ((int32_t)addr != -1) {
1821100787Sfenner		hi->name = strdup(hostname);
1822100787Sfenner		hi->n = 1;
1823100787Sfenner		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1824100787Sfenner		if (hi->addrs == NULL) {
1825100787Sfenner			Fprintf(stderr, "%s: calloc %s\n",
1826100787Sfenner			    prog, strerror(errno));
1827100787Sfenner			exit(1);
1828100787Sfenner		}
1829100787Sfenner		hi->addrs[0] = addr;
1830100787Sfenner		return (hi);
1831100787Sfenner	}
183218579Sfenner
183318579Sfenner	hp = gethostbyname(hostname);
183418579Sfenner	if (hp == NULL) {
183518579Sfenner		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
183618579Sfenner		exit(1);
183718579Sfenner	}
183818579Sfenner	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
183918579Sfenner		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
184018579Sfenner		exit(1);
184118579Sfenner	}
1842100787Sfenner	hi->name = strdup(hp->h_name);
1843100787Sfenner	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1844100787Sfenner		continue;
1845100787Sfenner	hi->n = n;
1846100787Sfenner	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1847100787Sfenner	if (hi->addrs == NULL) {
1848100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1849100787Sfenner		exit(1);
1850100787Sfenner	}
1851100787Sfenner	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1852100787Sfenner		memcpy(ap, *p, sizeof(*ap));
1853100787Sfenner	return (hi);
185418579Sfenner}
185518579Sfenner
1856100787Sfennervoid
1857100787Sfennerfreehostinfo(register struct hostinfo *hi)
185818579Sfenner{
1859100787Sfenner	if (hi->name != NULL) {
1860100787Sfenner		free(hi->name);
1861100787Sfenner		hi->name = NULL;
1862100787Sfenner	}
1863100787Sfenner	free((char *)hi->addrs);
1864100787Sfenner	free((char *)hi);
1865100787Sfenner}
186618579Sfenner
1867100787Sfennervoid
1868100787Sfennergetaddr(register u_int32_t *ap, register char *hostname)
1869100787Sfenner{
1870100787Sfenner	register struct hostinfo *hi;
1871100787Sfenner
1872100787Sfenner	hi = gethostinfo(hostname);
1873100787Sfenner	*ap = hi->addrs[0];
1874100787Sfenner	freehostinfo(hi);
1875100787Sfenner}
1876100787Sfenner
1877100787Sfennervoid
1878100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr)
1879100787Sfenner{
1880100787Sfenner
188118579Sfenner	memset(sin, 0, sizeof(*sin));
1882100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN
1883100787Sfenner	sin->sin_len = sizeof(*sin);
1884100787Sfenner#endif
188518579Sfenner	sin->sin_family = AF_INET;
1886100787Sfenner	sin->sin_addr.s_addr = addr;
188718579Sfenner}
188818579Sfenner
1889100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */
1890100787Sfennerint
1891100787Sfennerstr2val(register const char *str, register const char *what,
1892100787Sfenner    register int mi, register int ma)
189318579Sfenner{
1894100787Sfenner	register const char *cp;
1895100787Sfenner	register int val;
1896100787Sfenner	char *ep;
189718579Sfenner
1898100787Sfenner	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1899100787Sfenner		cp = str + 2;
1900100787Sfenner		val = (int)strtol(cp, &ep, 16);
1901100787Sfenner	} else
1902100787Sfenner		val = (int)strtol(str, &ep, 10);
1903100787Sfenner	if (*ep != '\0') {
1904100787Sfenner		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1905100787Sfenner		    prog, str, what);
190618579Sfenner		exit(1);
190718579Sfenner	}
1908100787Sfenner	if (val < mi && mi >= 0) {
1909100787Sfenner		if (mi == 0)
1910100787Sfenner			Fprintf(stderr, "%s: %s must be >= %d\n",
1911100787Sfenner			    prog, what, mi);
1912100787Sfenner		else
1913100787Sfenner			Fprintf(stderr, "%s: %s must be > %d\n",
1914100787Sfenner			    prog, what, mi - 1);
1915100787Sfenner		exit(1);
1916100787Sfenner	}
1917100787Sfenner	if (val > ma && ma >= 0) {
1918100787Sfenner		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1919100787Sfenner		exit(1);
1920100787Sfenner	}
1921100787Sfenner	return (val);
192218579Sfenner}
192318579Sfenner
1924100787Sfennerstruct outproto *
1925100787Sfennersetproto(char *pname)
1926100787Sfenner{
1927100787Sfenner	struct outproto *proto;
1928100787Sfenner	int i;
1929100787Sfenner
1930100787Sfenner	for (i = 0; protos[i].name != NULL; i++) {
1931100787Sfenner		if (strcasecmp(protos[i].name, pname) == 0) {
1932100787Sfenner			break;
1933100787Sfenner		}
1934100787Sfenner	}
1935100787Sfenner	proto = &protos[i];
1936100787Sfenner	if (proto->name == NULL) {	/* generic handler */
1937100787Sfenner		struct protoent *pe;
1938100787Sfenner		u_long pnum;
1939100787Sfenner
1940100787Sfenner		/* Determine the IP protocol number */
1941100787Sfenner		if ((pe = getprotobyname(pname)) != NULL)
1942100787Sfenner			pnum = pe->p_proto;
1943100787Sfenner		else
1944100787Sfenner			pnum = str2val(optarg, "proto number", 1, 255);
1945100787Sfenner		proto->num = pnum;
1946100787Sfenner	}
1947100787Sfenner	return proto;
1948100787Sfenner}
1949100787Sfenner
195067682Sobrienvoid
1951163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) {
1952163387Sdwmalone	int l;
1953163387Sdwmalone	int i;
1954163387Sdwmalone
1955163387Sdwmalone	for (i = 0; i < la; i++)
1956163387Sdwmalone		Printf("%02x", (unsigned int)a[i]);
1957163387Sdwmalone	Printf("\n");
1958163387Sdwmalone	l = (la <= lb) ? la : lb;
1959163387Sdwmalone	for (i = 0; i < l; i++)
1960163387Sdwmalone		if (a[i] == b[i])
1961163387Sdwmalone			Printf("__");
1962163387Sdwmalone		else
1963163387Sdwmalone			Printf("%02x", (unsigned int)b[i]);
1964163387Sdwmalone	for (; i < lb; i++)
1965163387Sdwmalone		Printf("%02x", (unsigned int)b[i]);
1966163387Sdwmalone	Printf("\n");
1967163387Sdwmalone}
1968163387Sdwmalone
1969163387Sdwmalone
1970163387Sdwmalonevoid
197118579Sfennerusage(void)
197218579Sfenner{
197318579Sfenner	extern char version[];
197418579Sfenner
197518579Sfenner	Fprintf(stderr, "Version %s\n", version);
1976100787Sfenner	Fprintf(stderr,
1977176428Srpaulo	    "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
1978100787Sfenner	    "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
1979176428Srpaulo	    "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog);
198018579Sfenner	exit(1);
198118579Sfenner}
1982