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: stable/11/contrib/traceroute/traceroute.c 339045 2018-10-01 14:39:59Z oshogbo $";
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>
206338475Soshogbo#include <sys/capsicum.h>
20718579Sfenner#include <sys/file.h>
20818579Sfenner#include <sys/ioctl.h>
20918579Sfenner#ifdef HAVE_SYS_SELECT_H
21018579Sfenner#include <sys/select.h>
21118579Sfenner#endif
21218579Sfenner#include <sys/socket.h>
21377816Sru#ifdef HAVE_SYS_SYSCTL_H
21477816Sru#include <sys/sysctl.h>
21577816Sru#endif
21618579Sfenner#include <sys/time.h>
21718579Sfenner
21818579Sfenner#include <netinet/in_systm.h>
21918579Sfenner#include <netinet/in.h>
22018579Sfenner#include <netinet/ip.h>
22118579Sfenner#include <netinet/ip_var.h>
22218579Sfenner#include <netinet/ip_icmp.h>
223283808Stuexen#include <netinet/sctp.h>
224332237Stuexen#include <netinet/sctp_header.h>
22518579Sfenner#include <netinet/udp.h>
22646542Sarchie#include <netinet/tcp.h>
227100789Sfenner#include <netinet/tcpip.h>
22818579Sfenner
22918579Sfenner#include <arpa/inet.h>
23018579Sfenner
231338475Soshogbo#ifdef HAVE_LIBCASPER
232338475Soshogbo#include <libcasper.h>
233338475Soshogbo#include <casper/cap_dns.h>
234338475Soshogbo#endif
235338475Soshogbo
23658804Sshin#ifdef	IPSEC
23758804Sshin#include <net/route.h>
238171135Sgnn#include <netipsec/ipsec.h>	/* XXX */
23958804Sshin#endif	/* IPSEC */
24058804Sshin
24118579Sfenner#include <ctype.h>
242100787Sfenner#include <err.h>
24318579Sfenner#include <errno.h>
244100787Sfenner#include <fcntl.h>
24518579Sfenner#ifdef HAVE_MALLOC_H
24618579Sfenner#include <malloc.h>
24718579Sfenner#endif
24818579Sfenner#include <memory.h>
24918579Sfenner#include <netdb.h>
25018579Sfenner#include <stdio.h>
25118579Sfenner#include <stdlib.h>
25218579Sfenner#include <string.h>
25318579Sfenner#include <unistd.h>
25418579Sfenner
255100787Sfenner/* rfc1716 */
256100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB
257100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
258100787Sfenner#endif
259100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE
260100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
261100787Sfenner#endif
262100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
263100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
264100787Sfenner#endif
265100787Sfenner
266100787Sfenner#include "findsaddr.h"
267100787Sfenner#include "ifaddrlist.h"
268176428Srpaulo#include "as.h"
269100787Sfenner#include "traceroute.h"
270100787Sfenner
27118579Sfenner/* Maximum number of gateways (include room for one noop) */
27218579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
27318579Sfenner
27418579Sfenner#ifndef MAXHOSTNAMELEN
27518579Sfenner#define MAXHOSTNAMELEN	64
27618579Sfenner#endif
27718579Sfenner
27818579Sfenner#define Fprintf (void)fprintf
27918579Sfenner#define Printf (void)printf
28018579Sfenner
28146542Sarchie/* What a GRE packet header looks like */
28246542Sarchiestruct grehdr {
28346542Sarchie	u_int16_t   flags;
28446542Sarchie	u_int16_t   proto;
28546542Sarchie	u_int16_t   length;	/* PPTP version of these fields */
28646542Sarchie	u_int16_t   callId;
28746542Sarchie};
28846542Sarchie#ifndef IPPROTO_GRE
28946542Sarchie#define IPPROTO_GRE	47
29046542Sarchie#endif
29146542Sarchie
29246542Sarchie/* For GRE, we prepare what looks like a PPTP packet */
29346542Sarchie#define GRE_PPTP_PROTO	0x880b
29446542Sarchie
295100787Sfenner/* Host name and address list */
296100787Sfennerstruct hostinfo {
297100787Sfenner	char *name;
298100787Sfenner	int n;
299100787Sfenner	u_int32_t *addrs;
300100787Sfenner};
301100787Sfenner
30218579Sfenner/* Data section of the probe packet */
30318579Sfennerstruct outdata {
30418579Sfenner	u_char seq;		/* sequence number of this packet */
30518579Sfenner	u_char ttl;		/* ttl packet left with */
30618579Sfenner	struct timeval tv;	/* time packet left */
30718579Sfenner};
30818579Sfenner
309100787Sfenner#ifndef HAVE_ICMP_NEXTMTU
310100787Sfenner/* Path MTU Discovery (RFC1191) */
311100787Sfennerstruct my_pmtu {
312100787Sfenner	u_short ipm_void;
313100787Sfenner	u_short ipm_nextmtu;
31446542Sarchie};
315100787Sfenner#endif
31646542Sarchie
31718579Sfenneru_char	packet[512];		/* last inbound (icmp) packet */
31818579Sfenner
31946542Sarchiestruct ip *outip;		/* last output ip packet */
320100787Sfenneru_char *outp;		/* last output inner protocol packet */
32118579Sfenner
322163387Sdwmalonestruct ip *hip = NULL;		/* Quoted IP header */
323163387Sdwmaloneint hiplen = 0;
324163387Sdwmalone
32518579Sfenner/* loose source route gateway list (including room for final destination) */
32618579Sfenneru_int32_t gwlist[NGATEWAYS + 1];
32718579Sfenner
32818579Sfennerint s;				/* receive (icmp) socket file descriptor */
32918579Sfennerint sndsock;			/* send (udp) socket file descriptor */
33018579Sfenner
33118579Sfennerstruct sockaddr whereto;	/* Who to try to reach */
332100787Sfennerstruct sockaddr wherefrom;	/* Who we are */
33318579Sfennerint packlen;			/* total length of packet */
33446542Sarchieint protlen;			/* length of protocol part of packet */
335100787Sfennerint minpacket;			/* min ip packet size */
33618579Sfennerint maxpacket = 32 * 1024;	/* max ip packet size */
337100787Sfennerint pmtu;			/* Path MTU Discovery (RFC1191) */
338100787Sfenneru_int pausemsecs;
33918579Sfenner
34018579Sfennerchar *prog;
34118579Sfennerchar *source;
34218579Sfennerchar *hostname;
343100787Sfennerchar *device;
344100787Sfennerstatic const char devnull[] = "/dev/null";
34518579Sfenner
346163387Sdwmaloneint nprobes = -1;
34777816Sruint max_ttl;
348100787Sfennerint first_ttl = 1;
34918579Sfenneru_short ident;
35046542Sarchieu_short port;			/* protocol specific base "port" */
35118579Sfenner
35218579Sfennerint options;			/* socket options */
35318579Sfennerint verbose;
35418579Sfennerint waittime = 5;		/* time to wait for response (in seconds) */
35518579Sfennerint nflag;			/* print addresses numerically */
356176428Srpauloint as_path;			/* print as numbers for each hop */
357176428Srpaulochar *as_server = NULL;
358176428Srpaulovoid *asn;
359100787Sfenner#ifdef CANT_HACK_IPCKSUM
360100787Sfennerint doipcksum = 0;		/* don't calculate ip checksums by default */
361100787Sfenner#else
362100787Sfennerint doipcksum = 1;		/* calculate ip checksums by default */
363100787Sfenner#endif
364100787Sfennerint optlen;			/* length of ip options */
365158424Scjcint fixedPort = 0;		/* Use fixed destination port for TCP and UDP */
366163387Sdwmaloneint printdiff = 0;		/* Print the difference between sent and quoted */
36718579Sfenner
36818579Sfennerextern int optind;
36918579Sfennerextern int opterr;
37018579Sfennerextern char *optarg;
37118579Sfenner
372338475Soshogbo#ifdef HAVE_LIBCASPER
373338475Soshogbostatic cap_channel_t *capdns;
374338475Soshogbo#endif
375338475Soshogbo
37618579Sfenner/* Forwards */
37718579Sfennerdouble	deltaT(struct timeval *, struct timeval *);
378100787Sfennervoid	freehostinfo(struct hostinfo *);
379100787Sfennervoid	getaddr(u_int32_t *, char *);
380100787Sfennerstruct	hostinfo *gethostinfo(char *);
381100535Sfenneru_short	in_cksum(u_short *, int);
382283808Stuexenu_int32_t sctp_crc32c(const void *, u_int32_t);
38318579Sfennerchar	*inetname(struct in_addr);
38418579Sfennerint	main(int, char **);
385283817Stuexenu_short p_cksum(struct ip *, u_short *, int, int);
38618579Sfennerint	packet_ok(u_char *, int, struct sockaddr_in *, int);
38718579Sfennerchar	*pr_type(u_char);
38818579Sfennervoid	print(u_char *, int, struct sockaddr_in *);
38958804Sshin#ifdef	IPSEC
39058804Sshinint	setpolicy __P((int so, char *policy));
39158804Sshin#endif
39246542Sarchievoid	send_probe(int, int);
393100787Sfennerstruct outproto *setproto(char *);
394100787Sfennerint	str2val(const char *, const char *, int, int);
39518579Sfennervoid	tvsub(struct timeval *, struct timeval *);
39667682Sobrienvoid usage(void);
397100787Sfennerint	wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
398163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int);
399100787Sfenner#ifndef HAVE_USLEEP
400100787Sfennerint	usleep(u_int);
401100787Sfenner#endif
40218579Sfenner
40346542Sarchievoid	udp_prep(struct outdata *);
40446542Sarchieint	udp_check(const u_char *, int);
405283817Stuexenvoid	udplite_prep(struct outdata *);
406283817Stuexenint	udplite_check(const u_char *, int);
40746542Sarchievoid	tcp_prep(struct outdata *);
40846542Sarchieint	tcp_check(const u_char *, int);
409283808Stuexenvoid	sctp_prep(struct outdata *);
410283808Stuexenint	sctp_check(const u_char *, int);
41146542Sarchievoid	gre_prep(struct outdata *);
41246542Sarchieint	gre_check(const u_char *, int);
41346542Sarchievoid	gen_prep(struct outdata *);
41446542Sarchieint	gen_check(const u_char *, int);
415100535Sfennervoid	icmp_prep(struct outdata *);
416100535Sfennerint	icmp_check(const u_char *, int);
41746542Sarchie
418100787Sfenner/* Descriptor structure for each outgoing protocol we support */
419100787Sfennerstruct outproto {
420100787Sfenner	char	*name;		/* name of protocol */
421163387Sdwmalone	const char *key;	/* An ascii key for the bytes of the header */
422100787Sfenner	u_char	num;		/* IP protocol number */
423100787Sfenner	u_short	hdrlen;		/* max size of protocol header */
424100787Sfenner	u_short	port;		/* default base protocol-specific "port" */
425100787Sfenner	void	(*prepare)(struct outdata *);
426100787Sfenner				/* finish preparing an outgoing packet */
427100787Sfenner	int	(*check)(const u_char *, int);
428100787Sfenner				/* check an incoming packet */
429100787Sfenner};
430100787Sfenner
43146542Sarchie/* List of supported protocols. The first one is the default. The last
43246542Sarchie   one is the handler for generic protocols not explicitly listed. */
43346542Sarchiestruct	outproto protos[] = {
43446542Sarchie	{
43546542Sarchie		"udp",
436163387Sdwmalone		"spt dpt len sum",
43746542Sarchie		IPPROTO_UDP,
43846542Sarchie		sizeof(struct udphdr),
43946542Sarchie		32768 + 666,
44046542Sarchie		udp_prep,
44146542Sarchie		udp_check
44246542Sarchie	},
44346542Sarchie	{
444283817Stuexen		"udplite",
445283817Stuexen		"spt dpt cov sum",
446283817Stuexen		IPPROTO_UDPLITE,
447283817Stuexen		sizeof(struct udphdr),
448283817Stuexen		32768 + 666,
449283817Stuexen		udplite_prep,
450283817Stuexen		udplite_check
451283817Stuexen	},
452283817Stuexen	{
45346542Sarchie		"tcp",
454163387Sdwmalone		"spt dpt seq     ack     xxflwin sum urp",
45546542Sarchie		IPPROTO_TCP,
45646542Sarchie		sizeof(struct tcphdr),
45746542Sarchie		32768 + 666,
45846542Sarchie		tcp_prep,
45946542Sarchie		tcp_check
46046542Sarchie	},
46146542Sarchie	{
462283808Stuexen		"sctp",
463283808Stuexen		"spt dpt vtag    crc     tyfllen tyfllen ",
464283808Stuexen		IPPROTO_SCTP,
465283808Stuexen		sizeof(struct sctphdr),
466283808Stuexen		32768 + 666,
467283808Stuexen		sctp_prep,
468283808Stuexen		sctp_check
469283808Stuexen	},
470283808Stuexen	{
47146542Sarchie		"gre",
472163387Sdwmalone		"flg pro len clid",
47346542Sarchie		IPPROTO_GRE,
47446542Sarchie		sizeof(struct grehdr),
47546542Sarchie		GRE_PPTP_PROTO,
47646542Sarchie		gre_prep,
47746542Sarchie		gre_check
47846542Sarchie	},
47946542Sarchie	{
480100535Sfenner		"icmp",
481163387Sdwmalone		"typ cod sum ",
482100535Sfenner		IPPROTO_ICMP,
483100535Sfenner		sizeof(struct icmp),
484100535Sfenner		0,
485100535Sfenner		icmp_prep,
486100535Sfenner		icmp_check
487100535Sfenner	},
488100535Sfenner	{
48946542Sarchie		NULL,
490283813Stuexen		"",
49146542Sarchie		0,
49246542Sarchie		2 * sizeof(u_short),
49346542Sarchie		0,
49446542Sarchie		gen_prep,
49546542Sarchie		gen_check
49646542Sarchie	},
49746542Sarchie};
49846542Sarchiestruct	outproto *proto = &protos[0];
49946542Sarchie
500163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id  off tlprsum srcip   dstip   opts";
501163387Sdwmalone
50218579Sfennerint
50318579Sfennermain(int argc, char **argv)
50418579Sfenner{
505100787Sfenner	register int op, code, n;
50618579Sfenner	register char *cp;
507100787Sfenner	register const char *err;
508100787Sfenner	register u_int32_t *ap;
509100787Sfenner	register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
51018579Sfenner	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
511100787Sfenner	register struct hostinfo *hi;
51218579Sfenner	int on = 1;
51318579Sfenner	register struct protoent *pe;
51418579Sfenner	register int ttl, probe, i;
51518579Sfenner	register int seq = 0;
516100787Sfenner	int tos = 0, settos = 0;
51718579Sfenner	register int lsrr = 0;
518100787Sfenner	register u_short off = 0;
519100787Sfenner	struct ifaddrlist *al;
520100787Sfenner	char errbuf[132];
52148221Sarchie	int requestPort = -1;
52218803Ssef	int sump = 0;
52318583Sfenner	int sockerrno;
524338475Soshogbo#ifdef HAVE_LIBCASPER
525338475Soshogbo	const char *types[] = { "NAME", "ADDR" };
526338475Soshogbo	int families[1];
527338475Soshogbo	cap_channel_t *casper;
528338475Soshogbo#endif
529338475Soshogbo	cap_rights_t rights;
530338475Soshogbo	bool cansandbox;
53118579Sfenner
532100787Sfenner	/* Insure the socket fds won't be 0, 1 or 2 */
533100787Sfenner	if (open(devnull, O_RDONLY) < 0 ||
534100787Sfenner	    open(devnull, O_RDONLY) < 0 ||
535100787Sfenner	    open(devnull, O_RDONLY) < 0) {
536100787Sfenner		Fprintf(stderr, "%s: open \"%s\": %s\n",
537100787Sfenner		    prog, devnull, strerror(errno));
538100787Sfenner		exit(1);
539100787Sfenner	}
54018583Sfenner	/*
54118583Sfenner	 * Do the setuid-required stuff first, then lose priveleges ASAP.
54218583Sfenner	 * Do error checking for these two calls where they appeared in
54318583Sfenner	 * the original code.
54418583Sfenner	 */
54518583Sfenner	cp = "icmp";
54618583Sfenner	pe = getprotobyname(cp);
54718583Sfenner	if (pe) {
54818583Sfenner		if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
54918583Sfenner			sockerrno = errno;
55018583Sfenner		else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
55118583Sfenner			sockerrno = errno;
55218583Sfenner	}
55318583Sfenner
554220968Ssimon	if (setuid(getuid()) != 0) {
555220968Ssimon		perror("setuid()");
556220968Ssimon		exit(1);
557220968Ssimon	}
55818583Sfenner
559338475Soshogbo#ifdef HAVE_LIBCASPER
560338475Soshogbo	casper = cap_init();
561338475Soshogbo	if (casper == NULL)
562338475Soshogbo		errx(1, "unable to create casper process");
563338475Soshogbo	capdns = cap_service_open(casper, "system.dns");
564338475Soshogbo	if (capdns == NULL)
565338475Soshogbo		errx(1, "unable to open system.dns service");
566338475Soshogbo	if (cap_dns_type_limit(capdns, types, 2) < 0)
567338475Soshogbo		errx(1, "unable to limit access to system.dns service");
568338475Soshogbo	families[0] = AF_INET;
569338475Soshogbo	if (cap_dns_family_limit(capdns, families, 1) < 0)
570338475Soshogbo		errx(1, "unable to limit access to system.dns service");
571338475Soshogbo#endif /* HAVE_LIBCASPER */
572338475Soshogbo
57377816Sru#ifdef IPCTL_DEFTTL
57477816Sru	{
57577816Sru		int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
57677816Sru		size_t sz = sizeof(max_ttl);
57777816Sru
578100787Sfenner		if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
579100787Sfenner			perror("sysctl(net.inet.ip.ttl)");
580100787Sfenner			exit(1);
581100787Sfenner		}
58277816Sru	}
583338475Soshogbo#else /* !IPCTL_DEFTTL */
58477816Sru	max_ttl = 30;
58577816Sru#endif
58677816Sru
587338475Soshogbo#ifdef HAVE_LIBCASPER
588338475Soshogbo	cap_close(casper);
589338475Soshogbo#endif
590338475Soshogbo
591100787Sfenner	if (argv[0] == NULL)
592100787Sfenner		prog = "traceroute";
593100787Sfenner	else if ((cp = strrchr(argv[0], '/')) != NULL)
59418579Sfenner		prog = cp + 1;
59518579Sfenner	else
59618579Sfenner		prog = argv[0];
59718579Sfenner
59818579Sfenner	opterr = 0;
599176428Srpaulo	while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
60018579Sfenner		switch (op) {
601176428Srpaulo		case 'a':
602176428Srpaulo			as_path = 1;
603176428Srpaulo			break;
604283784Stuexen
605176428Srpaulo		case 'A':
606176428Srpaulo			as_path = 1;
607176428Srpaulo			as_server = optarg;
608176428Srpaulo			break;
609283784Stuexen
61018579Sfenner		case 'd':
61118579Sfenner			options |= SO_DEBUG;
61218579Sfenner			break;
61318579Sfenner
614163387Sdwmalone		case 'D':
615163387Sdwmalone			printdiff = 1;
616163387Sdwmalone			break;
617163387Sdwmalone
618158424Scjc		case 'e':
619158424Scjc			fixedPort = 1;
620158424Scjc			break;
621158424Scjc
622100787Sfenner		case 'f':
623100787Sfenner		case 'M':	/* FreeBSD compat. */
624100787Sfenner			first_ttl = str2val(optarg, "first ttl", 1, 255);
625100787Sfenner			break;
626100787Sfenner
627100787Sfenner		case 'F':
628100787Sfenner			off = IP_DF;
629100787Sfenner			break;
630100787Sfenner
63118579Sfenner		case 'g':
63218579Sfenner			if (lsrr >= NGATEWAYS) {
63318579Sfenner				Fprintf(stderr,
63418579Sfenner				    "%s: No more than %d gateways\n",
63518579Sfenner				    prog, NGATEWAYS);
63618579Sfenner				exit(1);
63718579Sfenner			}
638100787Sfenner			getaddr(gwlist + lsrr, optarg);
63918579Sfenner			++lsrr;
64018579Sfenner			break;
64118579Sfenner
642100787Sfenner		case 'i':
643100787Sfenner			device = optarg;
64447071Sarchie			break;
64547071Sarchie
646100787Sfenner		case 'I':
647100787Sfenner			proto = setproto("icmp");
648100787Sfenner			break;
649100787Sfenner
65018579Sfenner		case 'm':
651100787Sfenner			max_ttl = str2val(optarg, "max ttl", 1, 255);
65218579Sfenner			break;
65318579Sfenner
65418579Sfenner		case 'n':
65518579Sfenner			++nflag;
65618579Sfenner			break;
65718579Sfenner
65846542Sarchie		case 'P':
659100787Sfenner			proto = setproto(optarg);
66046542Sarchie			break;
66146542Sarchie
66218579Sfenner		case 'p':
663100787Sfenner			requestPort = (u_short)str2val(optarg, "port",
664100787Sfenner			    1, (1 << 16) - 1);
66518579Sfenner			break;
66618579Sfenner
66718579Sfenner		case 'q':
668100787Sfenner			nprobes = str2val(optarg, "nprobes", 1, -1);
66918579Sfenner			break;
67018579Sfenner
67118579Sfenner		case 'r':
67218579Sfenner			options |= SO_DONTROUTE;
67318579Sfenner			break;
67418579Sfenner
67518579Sfenner		case 's':
67618579Sfenner			/*
67718579Sfenner			 * set the ip source address of the outbound
67818579Sfenner			 * probe (e.g., on a multi-homed host).
67918579Sfenner			 */
68018579Sfenner			source = optarg;
68118579Sfenner			break;
68218579Sfenner
683100787Sfenner		case 'S':
684100787Sfenner			sump = 1;
685100787Sfenner			break;
686100787Sfenner
68718579Sfenner		case 't':
688100787Sfenner			tos = str2val(optarg, "tos", 0, 255);
689100787Sfenner			++settos;
69018579Sfenner			break;
69118579Sfenner
69218579Sfenner		case 'v':
69318579Sfenner			++verbose;
69418579Sfenner			break;
69518579Sfenner
696100787Sfenner		case 'x':
697100787Sfenner			doipcksum = (doipcksum == 0);
698100787Sfenner			break;
699100787Sfenner
70018579Sfenner		case 'w':
701100787Sfenner			waittime = str2val(optarg, "wait time",
702169144Smaxim			    1, 24 * 60 * 60);
70318579Sfenner			break;
70418579Sfenner
705100787Sfenner		case 'z':
706100787Sfenner			pausemsecs = str2val(optarg, "pause msecs",
707100787Sfenner			    0, 60 * 60 * 1000);
708100787Sfenner			break;
709100787Sfenner
71018579Sfenner		default:
71118579Sfenner			usage();
71218579Sfenner		}
71318579Sfenner
71448221Sarchie	/* Set requested port, if any, else default for this protocol */
71548221Sarchie	port = (requestPort != -1) ? requestPort : proto->port;
71648221Sarchie
717163387Sdwmalone	if (nprobes == -1)
718163387Sdwmalone		nprobes = printdiff ? 1 : 3;
719163387Sdwmalone
720100787Sfenner	if (first_ttl > max_ttl) {
721100787Sfenner		Fprintf(stderr,
722100787Sfenner		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
723100787Sfenner		    prog, first_ttl, max_ttl);
72447071Sarchie		exit(1);
72547071Sarchie	}
72647071Sarchie
727100787Sfenner	if (!doipcksum)
728100787Sfenner		Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
729100787Sfenner
730100787Sfenner	if (lsrr > 0)
731100787Sfenner		optlen = (lsrr + 1) * sizeof(gwlist[0]);
732283786Stuexen	minpacket = sizeof(*outip) + proto->hdrlen + optlen;
733283786Stuexen	if (minpacket > 40)
734283786Stuexen		packlen = minpacket;
735283786Stuexen	else
736283786Stuexen		packlen = 40;
737100787Sfenner
73818579Sfenner	/* Process destination and optional packet size */
73918579Sfenner	switch (argc - optind) {
74018579Sfenner
74118579Sfenner	case 2:
742100787Sfenner		packlen = str2val(argv[optind + 1],
743100787Sfenner		    "packet length", minpacket, maxpacket);
744100787Sfenner		/* Fall through */
74518579Sfenner
74618579Sfenner	case 1:
747100787Sfenner		hostname = argv[optind];
748100787Sfenner		hi = gethostinfo(hostname);
749100787Sfenner		setsin(to, hi->addrs[0]);
750100787Sfenner		if (hi->n > 1)
751100787Sfenner			Fprintf(stderr,
752100787Sfenner		    "%s: Warning: %s has multiple addresses; using %s\n",
753100787Sfenner				prog, hostname, inet_ntoa(to->sin_addr));
754100787Sfenner		hostname = hi->name;
755100787Sfenner		hi->name = NULL;
756100787Sfenner		freehostinfo(hi);
75718579Sfenner		break;
75818579Sfenner
75918579Sfenner	default:
76018579Sfenner		usage();
76118579Sfenner	}
76218579Sfenner
76318579Sfenner#ifdef HAVE_SETLINEBUF
76418579Sfenner	setlinebuf (stdout);
76518579Sfenner#else
76618579Sfenner	setvbuf(stdout, NULL, _IOLBF, 0);
76718579Sfenner#endif
76818579Sfenner
76946542Sarchie	protlen = packlen - sizeof(*outip) - optlen;
770283808Stuexen	if ((proto->num == IPPROTO_SCTP) && (packlen & 3)) {
771283808Stuexen		Fprintf(stderr, "%s: packet length must be a multiple of 4\n",
772283808Stuexen		    prog);
773283808Stuexen		exit(1);
774283808Stuexen	}
77518579Sfenner
77618579Sfenner	outip = (struct ip *)malloc((unsigned)packlen);
77718579Sfenner	if (outip == NULL) {
77818579Sfenner		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
77918579Sfenner		exit(1);
78018579Sfenner	}
78118579Sfenner	memset((char *)outip, 0, packlen);
78218579Sfenner
78318579Sfenner	outip->ip_v = IPVERSION;
784100787Sfenner	if (settos)
785100787Sfenner		outip->ip_tos = tos;
786100787Sfenner#ifdef BYTESWAP_IP_HDR
78718579Sfenner	outip->ip_len = htons(packlen);
788100787Sfenner	outip->ip_off = htons(off);
78918579Sfenner#else
79018579Sfenner	outip->ip_len = packlen;
791100787Sfenner	outip->ip_off = off;
79218579Sfenner#endif
79346542Sarchie	outip->ip_p = proto->num;
794100787Sfenner	outp = (u_char *)(outip + 1);
79518579Sfenner#ifdef HAVE_RAW_OPTIONS
79618579Sfenner	if (lsrr > 0) {
79718579Sfenner		register u_char *optlist;
79818579Sfenner
799100787Sfenner		optlist = outp;
800100787Sfenner		outp += optlen;
80118579Sfenner
80218579Sfenner		/* final hop */
80318579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
80418579Sfenner
80518579Sfenner		outip->ip_dst.s_addr = gwlist[0];
80618579Sfenner
80718579Sfenner		/* force 4 byte alignment */
80818579Sfenner		optlist[0] = IPOPT_NOP;
80918579Sfenner		/* loose source route option */
81018579Sfenner		optlist[1] = IPOPT_LSRR;
81118579Sfenner		i = lsrr * sizeof(gwlist[0]);
81218579Sfenner		optlist[2] = i + 3;
81318579Sfenner		/* Pointer to LSRR addresses */
81418579Sfenner		optlist[3] = IPOPT_MINOFF;
81518579Sfenner		memcpy(optlist + 4, gwlist + 1, i);
81618579Sfenner	} else
81718579Sfenner#endif
81818579Sfenner		outip->ip_dst = to->sin_addr;
81918579Sfenner
820100787Sfenner	outip->ip_hl = (outp - (u_char *)outip) >> 2;
82118579Sfenner	ident = (getpid() & 0xffff) | 0x8000;
82218579Sfenner
82318583Sfenner	if (pe == NULL) {
82418579Sfenner		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
82518579Sfenner		exit(1);
82618579Sfenner	}
82718583Sfenner	if (s < 0) {
82818583Sfenner		errno = sockerrno;
82918579Sfenner		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
83018579Sfenner		exit(1);
83118579Sfenner	}
83218579Sfenner	if (options & SO_DEBUG)
83318579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
83418579Sfenner		    sizeof(on));
83518579Sfenner	if (options & SO_DONTROUTE)
83618579Sfenner		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
83718579Sfenner		    sizeof(on));
83818579Sfenner
83958804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
84058804Sshin	if (setpolicy(s, "in bypass") < 0)
84166809Skris		errx(1, "%s", ipsec_strerror());
84258804Sshin
84358804Sshin	if (setpolicy(s, "out bypass") < 0)
84466809Skris		errx(1, "%s", ipsec_strerror());
84558804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
84658804Sshin
84718583Sfenner	if (sndsock < 0) {
84818583Sfenner		errno = sockerrno;
84918579Sfenner		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
85018579Sfenner		exit(1);
85118579Sfenner	}
85218579Sfenner
85318579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
85418579Sfenner	if (lsrr > 0) {
85518579Sfenner		u_char optlist[MAX_IPOPTLEN];
85618579Sfenner
85718579Sfenner		cp = "ip";
85818579Sfenner		if ((pe = getprotobyname(cp)) == NULL) {
85918579Sfenner			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
86018579Sfenner			exit(1);
86118579Sfenner		}
86218579Sfenner
86318579Sfenner		/* final hop */
86418579Sfenner		gwlist[lsrr] = to->sin_addr.s_addr;
86518579Sfenner		++lsrr;
86618579Sfenner
86718579Sfenner		/* force 4 byte alignment */
86818579Sfenner		optlist[0] = IPOPT_NOP;
86918579Sfenner		/* loose source route option */
87018579Sfenner		optlist[1] = IPOPT_LSRR;
87118579Sfenner		i = lsrr * sizeof(gwlist[0]);
87218579Sfenner		optlist[2] = i + 3;
87318579Sfenner		/* Pointer to LSRR addresses */
87418579Sfenner		optlist[3] = IPOPT_MINOFF;
87518579Sfenner		memcpy(optlist + 4, gwlist, i);
87618579Sfenner
877100787Sfenner		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
878100787Sfenner		    (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
87918579Sfenner			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
88018579Sfenner			    prog, strerror(errno));
88118579Sfenner			exit(1);
88218579Sfenner		    }
88318579Sfenner	}
88418579Sfenner#endif
88518579Sfenner
88618579Sfenner#ifdef SO_SNDBUF
88718579Sfenner	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
88818579Sfenner	    sizeof(packlen)) < 0) {
88918579Sfenner		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
89018579Sfenner		exit(1);
89118579Sfenner	}
89218579Sfenner#endif
89318579Sfenner#ifdef IP_HDRINCL
89418579Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
89518579Sfenner	    sizeof(on)) < 0) {
89618579Sfenner		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
89718579Sfenner		exit(1);
89818579Sfenner	}
899100787Sfenner#else
900100787Sfenner#ifdef IP_TOS
901100787Sfenner	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
902100787Sfenner	    (char *)&tos, sizeof(tos)) < 0) {
903100787Sfenner		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
904100787Sfenner		    prog, tos, strerror(errno));
905100787Sfenner		exit(1);
906100787Sfenner	}
90718579Sfenner#endif
908100787Sfenner#endif
90918579Sfenner	if (options & SO_DEBUG)
91018579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
91118579Sfenner		    sizeof(on));
91218579Sfenner	if (options & SO_DONTROUTE)
91318579Sfenner		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
91418579Sfenner		    sizeof(on));
91518579Sfenner
916100787Sfenner	/* Get the interface address list */
917100787Sfenner	n = ifaddrlist(&al, errbuf);
918100787Sfenner	if (n < 0) {
919100787Sfenner		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
920100787Sfenner		exit(1);
921100787Sfenner	}
922100787Sfenner	if (n == 0) {
923100787Sfenner		Fprintf(stderr,
924100787Sfenner		    "%s: Can't find any network interfaces\n", prog);
925100787Sfenner		exit(1);
926100787Sfenner	}
927100787Sfenner
928100787Sfenner	/* Look for a specific device */
929100787Sfenner	if (device != NULL) {
930100787Sfenner		for (i = n; i > 0; --i, ++al)
931100787Sfenner			if (strcmp(device, al->device) == 0)
932100787Sfenner				break;
933100787Sfenner		if (i <= 0) {
934100787Sfenner			Fprintf(stderr, "%s: Can't find interface %.32s\n",
935100787Sfenner			    prog, device);
936100787Sfenner			exit(1);
93718579Sfenner		}
93818579Sfenner	}
93918579Sfenner
940100787Sfenner	/* Determine our source address */
941100787Sfenner	if (source == NULL) {
942100787Sfenner		/*
943100787Sfenner		 * If a device was specified, use the interface address.
944100787Sfenner		 * Otherwise, try to determine our source address.
945100787Sfenner		 */
946100787Sfenner		if (device != NULL)
947100787Sfenner			setsin(from, al->addr);
948100787Sfenner		else if ((err = findsaddr(to, from)) != NULL) {
949100787Sfenner			Fprintf(stderr, "%s: findsaddr: %s\n",
950100787Sfenner			    prog, err);
951100787Sfenner			exit(1);
952100787Sfenner		}
953100787Sfenner	} else {
954100787Sfenner		hi = gethostinfo(source);
955100787Sfenner		source = hi->name;
956100787Sfenner		hi->name = NULL;
957100787Sfenner		/*
958100787Sfenner		 * If the device was specified make sure it
959100787Sfenner		 * corresponds to the source address specified.
960100787Sfenner		 * Otherwise, use the first address (and warn if
961100787Sfenner		 * there are more than one).
962100787Sfenner		 */
963100787Sfenner		if (device != NULL) {
964100787Sfenner			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
965100787Sfenner				if (*ap == al->addr)
966100787Sfenner					break;
967100787Sfenner			if (i <= 0) {
968100787Sfenner				Fprintf(stderr,
969100787Sfenner				    "%s: %s is not on interface %.32s\n",
970100787Sfenner				    prog, source, device);
971100787Sfenner				exit(1);
972100787Sfenner			}
973100787Sfenner			setsin(from, *ap);
974100787Sfenner		} else {
975100787Sfenner			setsin(from, hi->addrs[0]);
976100787Sfenner			if (hi->n > 1)
977100787Sfenner				Fprintf(stderr,
978100787Sfenner			"%s: Warning: %s has multiple addresses; using %s\n",
979100787Sfenner				    prog, source, inet_ntoa(from->sin_addr));
980100787Sfenner		}
981100787Sfenner		freehostinfo(hi);
982100787Sfenner	}
983100787Sfenner
984100787Sfenner	outip->ip_src = from->sin_addr;
985128365Spb
986128365Spb	/* Check the source address (-s), if any, is valid */
987100787Sfenner	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
988100787Sfenner		Fprintf(stderr, "%s: bind: %s\n",
989100787Sfenner		    prog, strerror(errno));
990100787Sfenner		exit (1);
991100787Sfenner	}
992100787Sfenner
993176428Srpaulo	if (as_path) {
994176428Srpaulo		asn = as_setup(as_server);
995176428Srpaulo		if (asn == NULL) {
996176428Srpaulo			Fprintf(stderr, "%s: as_setup failed, AS# lookups"
997176428Srpaulo			    " disabled\n", prog);
998176428Srpaulo			(void)fflush(stderr);
999176428Srpaulo			as_path = 0;
1000176428Srpaulo		}
1001176428Srpaulo	}
1002283784Stuexen
1003338475Soshogbo	if (connect(sndsock, (struct sockaddr *)&whereto,
1004338475Soshogbo	    sizeof(whereto)) != 0) {
1005338475Soshogbo		Fprintf(stderr, "%s: connect: %s\n", prog, strerror(errno));
1006338475Soshogbo		exit(1);
1007338475Soshogbo	}
1008338475Soshogbo
1009338475Soshogbo#ifdef HAVE_LIBCASPER
1010338475Soshogbo	cansandbox = true;
1011338475Soshogbo#else
1012338475Soshogbo	if (nflag)
1013338475Soshogbo		cansandbox = true;
1014338475Soshogbo	else
1015338475Soshogbo		cansandbox = false;
1016338475Soshogbo#endif
1017338475Soshogbo
1018338475Soshogbo	/*
1019338475Soshogbo	 * Here we enter capability mode. Further down access to global
1020338475Soshogbo	 * namespaces (e.g filesystem) is restricted (see capsicum(4)).
1021338475Soshogbo	 * We must connect(2) our socket before this point.
1022338475Soshogbo	 */
1023338475Soshogbo	if (cansandbox && cap_enter() < 0) {
1024339045Soshogbo		if (errno != ENOSYS) {
1025339045Soshogbo			Fprintf(stderr, "%s: cap_enter: %s\n", prog,
1026339045Soshogbo			    strerror(errno));
1027339045Soshogbo			exit(1);
1028339045Soshogbo		} else {
1029339045Soshogbo			cansandbox = false;
1030339045Soshogbo		}
1031338475Soshogbo	}
1032338475Soshogbo
1033338475Soshogbo	cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT);
1034338475Soshogbo	if (cansandbox && cap_rights_limit(sndsock, &rights) < 0) {
1035338475Soshogbo		Fprintf(stderr, "%s: cap_rights_limit sndsock: %s\n", prog,
1036338475Soshogbo		    strerror(errno));
1037338475Soshogbo		exit(1);
1038338475Soshogbo	}
1039338475Soshogbo
1040338475Soshogbo	cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
1041338475Soshogbo	if (cansandbox && cap_rights_limit(s, &rights) < 0) {
1042338475Soshogbo		Fprintf(stderr, "%s: cap_rights_limit s: %s\n", prog,
1043338475Soshogbo		    strerror(errno));
1044338475Soshogbo		exit(1);
1045338475Soshogbo	}
1046338475Soshogbo
104758804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
104858804Sshin	if (setpolicy(sndsock, "in bypass") < 0)
104966809Skris		errx(1, "%s", ipsec_strerror());
105058804Sshin
105158804Sshin	if (setpolicy(sndsock, "out bypass") < 0)
105266809Skris		errx(1, "%s", ipsec_strerror());
105358804Sshin#endif	/* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
105458804Sshin
105518579Sfenner	Fprintf(stderr, "%s to %s (%s)",
105618579Sfenner	    prog, hostname, inet_ntoa(to->sin_addr));
105718579Sfenner	if (source)
105818579Sfenner		Fprintf(stderr, " from %s", source);
105918579Sfenner	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
106018579Sfenner	(void)fflush(stderr);
106118579Sfenner
1062100787Sfenner	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
106318579Sfenner		u_int32_t lastaddr = 0;
1064100787Sfenner		int gotlastaddr = 0;
106518579Sfenner		int got_there = 0;
106618579Sfenner		int unreachable = 0;
1067100787Sfenner		int sentfirst = 0;
106818695Ssef		int loss;
106918579Sfenner
107018579Sfenner		Printf("%2d ", ttl);
107118695Ssef		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
107218579Sfenner			register int cc;
107318579Sfenner			struct timeval t1, t2;
107418579Sfenner			register struct ip *ip;
107546542Sarchie			struct outdata outdata;
107618579Sfenner
1077100787Sfenner			if (sentfirst && pausemsecs > 0)
1078100787Sfenner				usleep(pausemsecs * 1000);
107946542Sarchie			/* Prepare outgoing data */
108046542Sarchie			outdata.seq = ++seq;
108146542Sarchie			outdata.ttl = ttl;
108246542Sarchie
108346542Sarchie			/* Avoid alignment problems by copying bytewise: */
1084211062Sed			(void)gettimeofday(&t1, NULL);
108546542Sarchie			memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
108646542Sarchie
108746542Sarchie			/* Finalize and send packet */
108846542Sarchie			(*proto->prepare)(&outdata);
108946542Sarchie			send_probe(seq, ttl);
1090100787Sfenner			++sentfirst;
109146542Sarchie
109246542Sarchie			/* Wait for a reply */
1093100787Sfenner			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
109418583Sfenner				double T;
109518583Sfenner				int precis;
109618583Sfenner
1097211062Sed				(void)gettimeofday(&t2, NULL);
1098100787Sfenner				i = packet_ok(packet, cc, from, seq);
109918579Sfenner				/* Skip short packet */
110018579Sfenner				if (i == 0)
110118579Sfenner					continue;
1102100787Sfenner				if (!gotlastaddr ||
1103100787Sfenner				    from->sin_addr.s_addr != lastaddr) {
1104154192Spav					if (gotlastaddr) printf("\n   ");
1105100787Sfenner					print(packet, cc, from);
1106100787Sfenner					lastaddr = from->sin_addr.s_addr;
1107100787Sfenner					++gotlastaddr;
110818579Sfenner				}
110918583Sfenner				T = deltaT(&t1, &t2);
111018583Sfenner#ifdef SANE_PRECISION
111118583Sfenner				if (T >= 1000.0)
111218583Sfenner					precis = 0;
111318583Sfenner				else if (T >= 100.0)
111418583Sfenner					precis = 1;
111518583Sfenner				else if (T >= 10.0)
111618583Sfenner					precis = 2;
111718583Sfenner				else
111818583Sfenner#endif
111918583Sfenner					precis = 3;
112018583Sfenner				Printf("  %.*f ms", precis, T);
1121163387Sdwmalone				if (printdiff) {
1122163387Sdwmalone					Printf("\n");
1123163387Sdwmalone					Printf("%*.*s%s\n",
1124163387Sdwmalone					    -(outip->ip_hl << 3),
1125163387Sdwmalone					    outip->ip_hl << 3,
1126163387Sdwmalone					    ip_hdr_key,
1127163387Sdwmalone					    proto->key);
1128163387Sdwmalone					pkt_compare((void *)outip, packlen,
1129163387Sdwmalone					    (void *)hip, hiplen);
1130163387Sdwmalone				}
1131100535Sfenner				if (i == -2) {
1132100567Sdcs#ifndef ARCHAIC
1133100535Sfenner					ip = (struct ip *)packet;
1134100535Sfenner					if (ip->ip_ttl <= 1)
1135100535Sfenner						Printf(" !");
1136100535Sfenner#endif
1137100535Sfenner					++got_there;
1138100535Sfenner					break;
1139100535Sfenner				}
114018579Sfenner				/* time exceeded in transit */
114118579Sfenner				if (i == -1)
114218579Sfenner					break;
114318579Sfenner				code = i - 1;
114418579Sfenner				switch (code) {
114518579Sfenner
114618579Sfenner				case ICMP_UNREACH_PORT:
114718579Sfenner#ifndef ARCHAIC
114818579Sfenner					ip = (struct ip *)packet;
114918579Sfenner					if (ip->ip_ttl <= 1)
115018579Sfenner						Printf(" !");
115118579Sfenner#endif
115218579Sfenner					++got_there;
115318579Sfenner					break;
115418579Sfenner
115518579Sfenner				case ICMP_UNREACH_NET:
115618579Sfenner					++unreachable;
115718579Sfenner					Printf(" !N");
115818579Sfenner					break;
115918579Sfenner
116018579Sfenner				case ICMP_UNREACH_HOST:
116118579Sfenner					++unreachable;
116218579Sfenner					Printf(" !H");
116318579Sfenner					break;
116418579Sfenner
116518579Sfenner				case ICMP_UNREACH_PROTOCOL:
116618579Sfenner					++got_there;
116718579Sfenner					Printf(" !P");
116818579Sfenner					break;
116918579Sfenner
117018579Sfenner				case ICMP_UNREACH_NEEDFRAG:
117118579Sfenner					++unreachable;
1172100787Sfenner					Printf(" !F-%d", pmtu);
117318579Sfenner					break;
117418579Sfenner
117518579Sfenner				case ICMP_UNREACH_SRCFAIL:
117618579Sfenner					++unreachable;
117718579Sfenner					Printf(" !S");
117818579Sfenner					break;
117918579Sfenner
1180159576Sdwmalone				case ICMP_UNREACH_NET_UNKNOWN:
1181159576Sdwmalone					++unreachable;
1182159576Sdwmalone					Printf(" !U");
1183159576Sdwmalone					break;
1184159576Sdwmalone
1185159576Sdwmalone				case ICMP_UNREACH_HOST_UNKNOWN:
1186159576Sdwmalone					++unreachable;
1187159576Sdwmalone					Printf(" !W");
1188159576Sdwmalone					break;
1189159576Sdwmalone
1190159576Sdwmalone				case ICMP_UNREACH_ISOLATED:
1191159576Sdwmalone					++unreachable;
1192159576Sdwmalone					Printf(" !I");
1193159576Sdwmalone					break;
1194159576Sdwmalone
1195159576Sdwmalone				case ICMP_UNREACH_NET_PROHIB:
1196159576Sdwmalone					++unreachable;
1197159576Sdwmalone					Printf(" !A");
1198159576Sdwmalone					break;
1199159576Sdwmalone
1200159576Sdwmalone				case ICMP_UNREACH_HOST_PROHIB:
1201159576Sdwmalone					++unreachable;
1202159576Sdwmalone					Printf(" !Z");
1203159576Sdwmalone					break;
1204159576Sdwmalone
1205159576Sdwmalone				case ICMP_UNREACH_TOSNET:
1206159576Sdwmalone					++unreachable;
1207159576Sdwmalone					Printf(" !Q");
1208159576Sdwmalone					break;
1209159576Sdwmalone
1210159576Sdwmalone				case ICMP_UNREACH_TOSHOST:
1211159576Sdwmalone					++unreachable;
1212159576Sdwmalone					Printf(" !T");
1213159576Sdwmalone					break;
1214159576Sdwmalone
121518579Sfenner				case ICMP_UNREACH_FILTER_PROHIB:
121618579Sfenner					++unreachable;
121718579Sfenner					Printf(" !X");
121818579Sfenner					break;
121918579Sfenner
1220100787Sfenner				case ICMP_UNREACH_HOST_PRECEDENCE:
1221100787Sfenner					++unreachable;
1222100787Sfenner					Printf(" !V");
1223100787Sfenner					break;
1224100787Sfenner
1225100787Sfenner				case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1226100787Sfenner					++unreachable;
1227100787Sfenner					Printf(" !C");
1228100787Sfenner					break;
1229100787Sfenner
123018579Sfenner				default:
123118579Sfenner					++unreachable;
123218579Sfenner					Printf(" !<%d>", code);
123318579Sfenner					break;
123418579Sfenner				}
123518579Sfenner				break;
123618579Sfenner			}
123718695Ssef			if (cc == 0) {
123818695Ssef				loss++;
123918579Sfenner				Printf(" *");
124018695Ssef			}
124118579Sfenner			(void)fflush(stdout);
124218579Sfenner		}
124318803Ssef		if (sump) {
124418811Ssef			Printf(" (%d%% loss)", (loss * 100) / nprobes);
124518803Ssef		}
124618579Sfenner		putchar('\n');
124718579Sfenner		if (got_there ||
124818579Sfenner		    (unreachable > 0 && unreachable >= nprobes - 1))
124918579Sfenner			break;
125018579Sfenner	}
1251176428Srpaulo	if (as_path)
1252176428Srpaulo		as_shutdown(asn);
125318579Sfenner	exit(0);
125418579Sfenner}
125518579Sfenner
125618579Sfennerint
125718579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp,
1258100787Sfenner    register const struct timeval *tp)
125918579Sfenner{
126066810Skris	fd_set *fdsp;
126166810Skris	size_t nfds;
126218579Sfenner	struct timeval now, wait;
126318579Sfenner	register int cc = 0;
126444086Sdes	register int error;
126518579Sfenner	int fromlen = sizeof(*fromp);
126618579Sfenner
126766810Skris	nfds = howmany(sock + 1, NFDBITS);
126898709Srobert	if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
126966810Skris		err(1, "malloc");
127098709Srobert	memset(fdsp, 0, nfds * sizeof(fd_mask));
127166810Skris	FD_SET(sock, fdsp);
127218579Sfenner
127318579Sfenner	wait.tv_sec = tp->tv_sec + waittime;
127418579Sfenner	wait.tv_usec = tp->tv_usec;
1275211062Sed	(void)gettimeofday(&now, NULL);
127618579Sfenner	tvsub(&wait, &now);
127744086Sdes	if (wait.tv_sec < 0) {
127844086Sdes		wait.tv_sec = 0;
127944086Sdes		wait.tv_usec = 1;
128044086Sdes	}
128118579Sfenner
128266810Skris	error = select(sock + 1, fdsp, NULL, NULL, &wait);
128344086Sdes	if (error == -1 && errno == EINVAL) {
128444086Sdes		Fprintf(stderr, "%s: botched select() args\n", prog);
128544086Sdes		exit(1);
128644086Sdes	}
128744086Sdes	if (error > 0)
1288100787Sfenner		cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
128918579Sfenner			    (struct sockaddr *)fromp, &fromlen);
129018579Sfenner
129166810Skris	free(fdsp);
129218579Sfenner	return(cc);
129318579Sfenner}
129418579Sfenner
1295100787Sfennervoid
1296100787Sfennersend_probe(int seq, int ttl)
1297100787Sfenner{
1298100787Sfenner	register int cc;
1299100787Sfenner
1300100787Sfenner	outip->ip_ttl = ttl;
1301100787Sfenner	outip->ip_id = htons(ident + seq);
1302100787Sfenner
1303100787Sfenner	/* XXX undocumented debugging hack */
1304100787Sfenner	if (verbose > 1) {
1305100787Sfenner		register const u_short *sp;
1306100787Sfenner		register int nshorts, i;
1307100787Sfenner
1308100787Sfenner		sp = (u_short *)outip;
1309100787Sfenner		nshorts = (u_int)packlen / sizeof(u_short);
1310100787Sfenner		i = 0;
1311100787Sfenner		Printf("[ %d bytes", packlen);
1312100787Sfenner		while (--nshorts >= 0) {
1313100787Sfenner			if ((i++ % 8) == 0)
1314100787Sfenner				Printf("\n\t");
1315100787Sfenner			Printf(" %04x", ntohs(*sp++));
1316100787Sfenner		}
1317100787Sfenner		if (packlen & 1) {
1318100787Sfenner			if ((i % 8) == 0)
1319100787Sfenner				Printf("\n\t");
1320100787Sfenner			Printf(" %02x", *(u_char *)sp);
1321100787Sfenner		}
1322100787Sfenner		Printf("]\n");
1323100787Sfenner	}
1324100787Sfenner
1325100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL)
1326100787Sfenner	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1327100787Sfenner	    (char *)&ttl, sizeof(ttl)) < 0) {
1328100787Sfenner		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1329100787Sfenner		    prog, ttl, strerror(errno));
1330100787Sfenner		exit(1);
1331100787Sfenner	}
1332100787Sfenner#endif
1333100787Sfenner
1334338475Soshogbo	cc = send(sndsock, (char *)outip, packlen, 0);
1335100787Sfenner	if (cc < 0 || cc != packlen)  {
1336100787Sfenner		if (cc < 0)
1337100787Sfenner			Fprintf(stderr, "%s: sendto: %s\n",
1338100787Sfenner			    prog, strerror(errno));
1339100787Sfenner		Printf("%s: wrote %s %d chars, ret=%d\n",
1340100787Sfenner		    prog, hostname, packlen, cc);
1341100787Sfenner		(void)fflush(stdout);
1342100787Sfenner	}
1343100787Sfenner}
1344100787Sfenner
134558804Sshin#if	defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
134658804Sshinint
134758804Sshinsetpolicy(so, policy)
134858804Sshin	int so;
134958804Sshin	char *policy;
135058804Sshin{
135158804Sshin	char *buf;
135258804Sshin
135358804Sshin	buf = ipsec_set_policy(policy, strlen(policy));
135458804Sshin	if (buf == NULL) {
135566809Skris		warnx("%s", ipsec_strerror());
135658804Sshin		return -1;
135758804Sshin	}
135858804Sshin	(void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
135958804Sshin		buf, ipsec_get_policylen(buf));
136058804Sshin
136158804Sshin	free(buf);
136258804Sshin
136358804Sshin	return 0;
136458804Sshin}
136558804Sshin#endif
136658804Sshin
136718579Sfennerdouble
136818579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p)
136918579Sfenner{
137018579Sfenner	register double dt;
137118579Sfenner
137218579Sfenner	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
137318579Sfenner	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
137418579Sfenner	return (dt);
137518579Sfenner}
137618579Sfenner
137718579Sfenner/*
137818579Sfenner * Convert an ICMP "type" field to a printable string.
137918579Sfenner */
138018579Sfennerchar *
138118579Sfennerpr_type(register u_char t)
138218579Sfenner{
138318579Sfenner	static char *ttab[] = {
138418579Sfenner	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
138518579Sfenner	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
138618579Sfenner	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
138718579Sfenner	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
138818579Sfenner	"Info Reply"
138918579Sfenner	};
139018579Sfenner
139118579Sfenner	if (t > 16)
139218579Sfenner		return("OUT-OF-RANGE");
139318579Sfenner
139418579Sfenner	return(ttab[t]);
139518579Sfenner}
139618579Sfenner
139718579Sfennerint
139818579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
139918579Sfenner    register int seq)
140018579Sfenner{
140118579Sfenner	register struct icmp *icp;
140218579Sfenner	register u_char type, code;
140318579Sfenner	register int hlen;
140418579Sfenner#ifndef ARCHAIC
140518579Sfenner	register struct ip *ip;
140618579Sfenner
140718579Sfenner	ip = (struct ip *) buf;
140818579Sfenner	hlen = ip->ip_hl << 2;
140918579Sfenner	if (cc < hlen + ICMP_MINLEN) {
141018579Sfenner		if (verbose)
141118579Sfenner			Printf("packet too short (%d bytes) from %s\n", cc,
141218579Sfenner				inet_ntoa(from->sin_addr));
141318579Sfenner		return (0);
141418579Sfenner	}
141518579Sfenner	cc -= hlen;
141618579Sfenner	icp = (struct icmp *)(buf + hlen);
141718579Sfenner#else
141818579Sfenner	icp = (struct icmp *)buf;
141918579Sfenner#endif
142018579Sfenner	type = icp->icmp_type;
142118579Sfenner	code = icp->icmp_code;
1422100787Sfenner	/* Path MTU Discovery (RFC1191) */
1423100787Sfenner	if (code != ICMP_UNREACH_NEEDFRAG)
1424100787Sfenner		pmtu = 0;
1425100787Sfenner	else {
1426100787Sfenner#ifdef HAVE_ICMP_NEXTMTU
1427100787Sfenner		pmtu = ntohs(icp->icmp_nextmtu);
1428100787Sfenner#else
1429100787Sfenner		pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1430100787Sfenner#endif
1431100787Sfenner	}
1432100535Sfenner	if (type == ICMP_ECHOREPLY
1433100535Sfenner	    && proto->num == IPPROTO_ICMP
1434124859Scperciva	    && (*proto->check)((u_char *)icp, (u_char)seq))
1435100535Sfenner		return -2;
143618579Sfenner	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
143718579Sfenner	    type == ICMP_UNREACH) {
143846542Sarchie		u_char *inner;
143918579Sfenner
144018579Sfenner		hip = &icp->icmp_ip;
1441163387Sdwmalone		hiplen = ((u_char *)icp + cc) - (u_char *)hip;
144218579Sfenner		hlen = hip->ip_hl << 2;
144346542Sarchie		inner = (u_char *)((u_char *)hip + hlen);
1444283785Stuexen		if (hlen + 16 <= cc
144546542Sarchie		    && hip->ip_p == proto->num
1446124859Scperciva		    && (*proto->check)(inner, (u_char)seq))
144718579Sfenner			return (type == ICMP_TIMXCEED ? -1 : code + 1);
144818579Sfenner	}
144918579Sfenner#ifndef ARCHAIC
145018579Sfenner	if (verbose) {
145118579Sfenner		register int i;
145218579Sfenner		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
145318579Sfenner
145418579Sfenner		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
145518579Sfenner		Printf("%s: icmp type %d (%s) code %d\n",
145618579Sfenner		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1457283806Stuexen		for (i = 4; i <= cc - ICMP_MINLEN; i += sizeof(*lp))
1458283806Stuexen			Printf("%2d: %8.8x\n", i, ntohl(*lp++));
145918579Sfenner	}
146018579Sfenner#endif
146118579Sfenner	return(0);
146218579Sfenner}
146318579Sfenner
146446542Sarchievoid
1465100535Sfennericmp_prep(struct outdata *outdata)
1466100535Sfenner{
1467100787Sfenner	struct icmp *const icmpheader = (struct icmp *) outp;
1468100535Sfenner
1469100535Sfenner	icmpheader->icmp_type = ICMP_ECHO;
1470100535Sfenner	icmpheader->icmp_id = htons(ident);
1471100535Sfenner	icmpheader->icmp_seq = htons(outdata->seq);
1472100535Sfenner	icmpheader->icmp_cksum = 0;
1473100789Sfenner	icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
1474100535Sfenner	if (icmpheader->icmp_cksum == 0)
1475100535Sfenner		icmpheader->icmp_cksum = 0xffff;
1476100535Sfenner}
1477100535Sfenner
1478100535Sfennerint
1479100535Sfennericmp_check(const u_char *data, int seq)
1480100535Sfenner{
1481100535Sfenner	struct icmp *const icmpheader = (struct icmp *) data;
1482100535Sfenner
1483100535Sfenner	return (icmpheader->icmp_id == htons(ident)
1484100535Sfenner	    && icmpheader->icmp_seq == htons(seq));
1485100535Sfenner}
1486100535Sfenner
1487100535Sfennervoid
148846542Sarchieudp_prep(struct outdata *outdata)
148946542Sarchie{
1490100787Sfenner	struct udphdr *const outudp = (struct udphdr *) outp;
149118579Sfenner
1492158424Scjc	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1493158424Scjc	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1494100787Sfenner	outudp->uh_ulen = htons((u_short)protlen);
1495100789Sfenner	outudp->uh_sum = 0;
1496100787Sfenner	if (doipcksum) {
1497283817Stuexen	    u_short sum = p_cksum(outip, (u_short*)outudp, protlen, protlen);
1498100789Sfenner	    outudp->uh_sum = (sum) ? sum : 0xffff;
1499100787Sfenner	}
1500100789Sfenner
1501100789Sfenner	return;
150246542Sarchie}
150346542Sarchie
150446542Sarchieint
150546542Sarchieudp_check(const u_char *data, int seq)
150646542Sarchie{
150746542Sarchie	struct udphdr *const udp = (struct udphdr *) data;
150846542Sarchie
1509158424Scjc	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1510158424Scjc	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
151146542Sarchie}
151246542Sarchie
151318579Sfennervoid
1514283817Stuexenudplite_prep(struct outdata *outdata)
1515283817Stuexen{
1516283817Stuexen	struct udphdr *const outudp = (struct udphdr *) outp;
1517283817Stuexen
1518283817Stuexen	outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
1519283817Stuexen	outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1520283817Stuexen	outudp->uh_ulen = htons(8);
1521283817Stuexen	outudp->uh_sum = 0;
1522283817Stuexen	if (doipcksum) {
1523283817Stuexen	    u_short sum = p_cksum(outip, (u_short*)outudp, protlen, 8);
1524283817Stuexen	    outudp->uh_sum = (sum) ? sum : 0xffff;
1525283817Stuexen	}
1526283817Stuexen
1527283817Stuexen	return;
1528283817Stuexen}
1529283817Stuexen
1530283817Stuexenint
1531283817Stuexenudplite_check(const u_char *data, int seq)
1532283817Stuexen{
1533283817Stuexen	struct udphdr *const udp = (struct udphdr *) data;
1534283817Stuexen
1535283817Stuexen	return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
1536283817Stuexen	    ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
1537283817Stuexen}
1538283817Stuexen
1539283817Stuexenvoid
154046542Sarchietcp_prep(struct outdata *outdata)
154146542Sarchie{
1542100787Sfenner	struct tcphdr *const tcp = (struct tcphdr *) outp;
154346542Sarchie
154446542Sarchie	tcp->th_sport = htons(ident);
1545158424Scjc	tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
1546234701Stuexen	tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
154746542Sarchie	tcp->th_ack = 0;
154846542Sarchie	tcp->th_off = 5;
154946542Sarchie	tcp->th_flags = TH_SYN;
1550100789Sfenner	tcp->th_sum = 0;
1551100789Sfenner
1552283819Stuexen	if (doipcksum)
1553283819Stuexen	    tcp->th_sum = p_cksum(outip, (u_short*)tcp, protlen, protlen);
155446542Sarchie}
155546542Sarchie
155646542Sarchieint
155746542Sarchietcp_check(const u_char *data, int seq)
155846542Sarchie{
155946542Sarchie	struct tcphdr *const tcp = (struct tcphdr *) data;
156046542Sarchie
156146542Sarchie	return (ntohs(tcp->th_sport) == ident
1562234701Stuexen	    && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq)
1563234701Stuexen	    && tcp->th_seq == (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport));
156446542Sarchie}
156546542Sarchie
156646542Sarchievoid
1567283808Stuexensctp_prep(struct outdata *outdata)
1568283808Stuexen{
1569283808Stuexen	struct sctphdr *const sctp = (struct sctphdr *) outp;
1570283808Stuexen	struct sctp_chunkhdr *chk;
1571332237Stuexen	struct sctp_init_chunk *init;
1572332237Stuexen	struct sctp_paramhdr *param;
1573283808Stuexen
1574283808Stuexen	sctp->src_port = htons(ident);
1575283808Stuexen	sctp->dest_port = htons(port + (fixedPort ? 0 : outdata->seq));
1576332237Stuexen	if (protlen >= (int)(sizeof(struct sctphdr) +
1577332237Stuexen	    sizeof(struct sctp_init_chunk))) {
1578332237Stuexen		sctp->v_tag = 0;
1579332237Stuexen	} else {
1580332237Stuexen		sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
1581332237Stuexen	}
1582283808Stuexen	sctp->checksum = htonl(0);
1583332237Stuexen	if (protlen >= (int)(sizeof(struct sctphdr) +
1584332237Stuexen	    sizeof(struct sctp_init_chunk))) {
1585332237Stuexen		/*
1586332237Stuexen		 * Send a packet containing an INIT chunk. This works
1587332237Stuexen		 * better in case of firewalls on the path, but
1588332237Stuexen		 * results in a probe packet containing at least
1589332237Stuexen		 * 32 bytes of payload. For shorter payloads, use
1590332237Stuexen		 * SHUTDOWN-ACK chunks.
1591332237Stuexen		 */
1592332237Stuexen		init = (struct sctp_init_chunk *)(sctp + 1);
1593332237Stuexen		init->ch.chunk_type = SCTP_INITIATION;
1594332237Stuexen		init->ch.chunk_flags = 0;
1595332237Stuexen		init->ch.chunk_length = htons((u_int16_t)(protlen -
1596332237Stuexen		    sizeof(struct sctphdr)));
1597332237Stuexen		init->init.initiate_tag = (sctp->src_port << 16) |
1598332237Stuexen		    sctp->dest_port;
1599332237Stuexen		init->init.a_rwnd = htonl(1500);
1600332237Stuexen		init->init.num_outbound_streams = htons(1);
1601332237Stuexen		init->init.num_inbound_streams = htons(1);
1602332237Stuexen		init->init.initial_tsn = htonl(0);
1603332237Stuexen		if (protlen >= (int)(sizeof(struct sctphdr) +
1604332237Stuexen		    sizeof(struct sctp_init_chunk) +
1605332237Stuexen		    sizeof(struct sctp_paramhdr))) {
1606332237Stuexen			param = (struct sctp_paramhdr *)(init + 1);
1607332237Stuexen			param->param_type = htons(SCTP_PAD);
1608332237Stuexen			param->param_length =
1609332237Stuexen			    htons((u_int16_t)(protlen -
1610332237Stuexen			    sizeof(struct sctphdr) -
1611332237Stuexen			    sizeof(struct sctp_init_chunk)));
1612332237Stuexen		}
1613332237Stuexen	} else {
1614332237Stuexen		/*
1615332237Stuexen		 * Send a packet containing a SHUTDOWN-ACK chunk,
1616332237Stuexen		 * possibly followed by a PAD chunk.
1617332237Stuexen		 */
1618332237Stuexen		if (protlen >=
1619332237Stuexen		    (int)(sizeof(struct sctphdr) +
1620332237Stuexen		    sizeof(struct sctp_chunkhdr))) {
1621332237Stuexen			chk = (struct sctp_chunkhdr *)(sctp + 1);
1622332237Stuexen			chk->chunk_type = SCTP_SHUTDOWN_ACK;
1623332237Stuexen			chk->chunk_flags = 0;
1624332237Stuexen			chk->chunk_length = htons(4);
1625332237Stuexen		}
1626332237Stuexen		if (protlen >=
1627332237Stuexen		    (int)(sizeof(struct sctphdr) +
1628332237Stuexen		    2 * sizeof(struct sctp_chunkhdr))) {
1629332237Stuexen			chk = chk + 1;
1630332237Stuexen			chk->chunk_type = SCTP_PAD_CHUNK;
1631332237Stuexen			chk->chunk_flags = 0;
1632332237Stuexen			chk->chunk_length = htons(protlen -
1633332237Stuexen			    (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
1634332237Stuexen		}
1635283808Stuexen	}
1636283808Stuexen	if (doipcksum) {
1637283808Stuexen		sctp->checksum = sctp_crc32c(sctp, protlen);
1638283808Stuexen	}
1639283808Stuexen}
1640283808Stuexen
1641283808Stuexenint
1642283808Stuexensctp_check(const u_char *data, int seq)
1643283808Stuexen{
1644283808Stuexen	struct sctphdr *const sctp = (struct sctphdr *) data;
1645283808Stuexen
1646332237Stuexen	if (ntohs(sctp->src_port) != ident ||
1647332237Stuexen	    ntohs(sctp->dest_port) != port + (fixedPort ? 0 : seq))
1648332237Stuexen		return (0);
1649332237Stuexen	if (protlen < (int)(sizeof(struct sctphdr) +
1650332237Stuexen	    sizeof(struct sctp_init_chunk))) {
1651332237Stuexen		return (sctp->v_tag ==
1652332237Stuexen		    (u_int32_t)((sctp->src_port << 16) | sctp->dest_port));
1653332237Stuexen	} else {
1654332237Stuexen		/*
1655332237Stuexen		 * Don't verify the initiate_tag, since it is not available,
1656332237Stuexen		 * most of the time.
1657332237Stuexen		 */
1658332237Stuexen		return (sctp->v_tag == 0);
1659332237Stuexen	}
1660283808Stuexen}
1661283808Stuexen
1662283808Stuexenvoid
166346542Sarchiegre_prep(struct outdata *outdata)
166446542Sarchie{
1665100787Sfenner	struct grehdr *const gre = (struct grehdr *) outp;
166646542Sarchie
166746542Sarchie	gre->flags = htons(0x2001);
166846542Sarchie	gre->proto = htons(port);
166946542Sarchie	gre->length = 0;
167046542Sarchie	gre->callId = htons(ident + outdata->seq);
167146542Sarchie}
167246542Sarchie
167346542Sarchieint
167446542Sarchiegre_check(const u_char *data, int seq)
167546542Sarchie{
167646542Sarchie	struct grehdr *const gre = (struct grehdr *) data;
167746542Sarchie
167846542Sarchie	return(ntohs(gre->proto) == port
167946542Sarchie	    && ntohs(gre->callId) == ident + seq);
168046542Sarchie}
168146542Sarchie
168246542Sarchievoid
168346542Sarchiegen_prep(struct outdata *outdata)
168446542Sarchie{
1685100787Sfenner	u_int16_t *const ptr = (u_int16_t *) outp;
168646542Sarchie
168746542Sarchie	ptr[0] = htons(ident);
168846542Sarchie	ptr[1] = htons(port + outdata->seq);
168946542Sarchie}
169046542Sarchie
169146542Sarchieint
169246542Sarchiegen_check(const u_char *data, int seq)
169346542Sarchie{
169446542Sarchie	u_int16_t *const ptr = (u_int16_t *) data;
169546542Sarchie
169646542Sarchie	return(ntohs(ptr[0]) == ident
169746542Sarchie	    && ntohs(ptr[1]) == port + seq);
169846542Sarchie}
169946542Sarchie
170046542Sarchievoid
170118579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from)
170218579Sfenner{
170318579Sfenner	register struct ip *ip;
170418579Sfenner	register int hlen;
1705196475Sume	char addr[INET_ADDRSTRLEN];
170618579Sfenner
170718579Sfenner	ip = (struct ip *) buf;
170818579Sfenner	hlen = ip->ip_hl << 2;
170918579Sfenner	cc -= hlen;
171018579Sfenner
1711196475Sume	strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
1712196475Sume
1713176428Srpaulo	if (as_path)
1714196475Sume		Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
1715176428Srpaulo
171618579Sfenner	if (nflag)
1717196475Sume		Printf(" %s", addr);
171818579Sfenner	else
1719196475Sume		Printf(" %s (%s)", inetname(from->sin_addr), addr);
172018579Sfenner
172118579Sfenner	if (verbose)
172218579Sfenner		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
172318579Sfenner}
172418579Sfenner
172518579Sfenner/*
1726100789Sfenner * Checksum routine for UDP and TCP headers.
1727100789Sfenner */
1728283784Stuexenu_short
1729283817Stuexenp_cksum(struct ip *ip, u_short *data, int len, int cov)
1730100789Sfenner{
1731100789Sfenner	static struct ipovly ipo;
1732216184Suqs	u_short sum[2];
1733100789Sfenner
1734100789Sfenner	ipo.ih_pr = ip->ip_p;
1735100789Sfenner	ipo.ih_len = htons(len);
1736100789Sfenner	ipo.ih_src = ip->ip_src;
1737100789Sfenner	ipo.ih_dst = ip->ip_dst;
1738100789Sfenner
1739216184Suqs	sum[1] = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
1740283817Stuexen	sum[0] = in_cksum(data, cov);                   /* payload data cksum */
1741100789Sfenner
1742216184Suqs	return ~in_cksum(sum, sizeof(sum));
1743100789Sfenner}
1744100789Sfenner
1745100789Sfenner/*
174618579Sfenner * Checksum routine for Internet Protocol family headers (C Version)
174718579Sfenner */
1748100535Sfenneru_short
174918579Sfennerin_cksum(register u_short *addr, register int len)
175018579Sfenner{
175118579Sfenner	register int nleft = len;
175218579Sfenner	register u_short *w = addr;
175318579Sfenner	register u_short answer;
175418579Sfenner	register int sum = 0;
175518579Sfenner
175618579Sfenner	/*
175718579Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
175818579Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
175918579Sfenner	 *  back all the carry bits from the top 16 bits into the lower
176018579Sfenner	 *  16 bits.
176118579Sfenner	 */
176218579Sfenner	while (nleft > 1)  {
176318579Sfenner		sum += *w++;
176418579Sfenner		nleft -= 2;
176518579Sfenner	}
176618579Sfenner
176718579Sfenner	/* mop up an odd byte, if necessary */
176818579Sfenner	if (nleft == 1)
176918579Sfenner		sum += *(u_char *)w;
177018579Sfenner
177118579Sfenner	/*
177218579Sfenner	 * add back carry outs from top 16 bits to low 16 bits
177318579Sfenner	 */
177418579Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
177518579Sfenner	sum += (sum >> 16);			/* add carry */
177618579Sfenner	answer = ~sum;				/* truncate to 16 bits */
177718579Sfenner	return (answer);
177818579Sfenner}
177918579Sfenner
178018579Sfenner/*
1781283808Stuexen * CRC32C routine for the Stream Control Transmission Protocol
1782283808Stuexen */
1783283808Stuexen
1784283808Stuexen#define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
1785283808Stuexen
1786283808Stuexenstatic u_int32_t crc_c[256] = {
1787283808Stuexen	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
1788283808Stuexen	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
1789283808Stuexen	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
1790283808Stuexen	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
1791283808Stuexen	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
1792283808Stuexen	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
1793283808Stuexen	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
1794283808Stuexen	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
1795283808Stuexen	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
1796283808Stuexen	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
1797283808Stuexen	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
1798283808Stuexen	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
1799283808Stuexen	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
1800283808Stuexen	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
1801283808Stuexen	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
1802283808Stuexen	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
1803283808Stuexen	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
1804283808Stuexen	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
1805283808Stuexen	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
1806283808Stuexen	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
1807283808Stuexen	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
1808283808Stuexen	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
1809283808Stuexen	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
1810283808Stuexen	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
1811283808Stuexen	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
1812283808Stuexen	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
1813283808Stuexen	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
1814283808Stuexen	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
1815283808Stuexen	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
1816283808Stuexen	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
1817283808Stuexen	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
1818283808Stuexen	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
1819283808Stuexen	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
1820283808Stuexen	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
1821283808Stuexen	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
1822283808Stuexen	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
1823283808Stuexen	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
1824283808Stuexen	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
1825283808Stuexen	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
1826283808Stuexen	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
1827283808Stuexen	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
1828283808Stuexen	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
1829283808Stuexen	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
1830283808Stuexen	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
1831283808Stuexen	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
1832283808Stuexen	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
1833283808Stuexen	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
1834283808Stuexen	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
1835283808Stuexen	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
1836283808Stuexen	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
1837283808Stuexen	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
1838283808Stuexen	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
1839283808Stuexen	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
1840283808Stuexen	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
1841283808Stuexen	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
1842283808Stuexen	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
1843283808Stuexen	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
1844283808Stuexen	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
1845283808Stuexen	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
1846283808Stuexen	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
1847283808Stuexen	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
1848283808Stuexen	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
1849283808Stuexen	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
1850283808Stuexen	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
1851283808Stuexen};
1852283808Stuexen
1853283808Stuexenu_int32_t
1854283808Stuexensctp_crc32c(const void *packet, u_int32_t len)
1855283808Stuexen{
1856283808Stuexen	u_int32_t i, crc32c;
1857283808Stuexen	u_int8_t byte0, byte1, byte2, byte3;
1858283808Stuexen	const u_int8_t *buf = (const u_int8_t *)packet;
1859283808Stuexen
1860283808Stuexen	crc32c = ~0;
1861283808Stuexen	for (i = 0; i < len; i++)
1862283808Stuexen		CRC32C(crc32c, buf[i]);
1863283808Stuexen	crc32c = ~crc32c;
1864283808Stuexen	byte0  = crc32c & 0xff;
1865283808Stuexen	byte1  = (crc32c>>8) & 0xff;
1866283808Stuexen	byte2  = (crc32c>>16) & 0xff;
1867283808Stuexen	byte3  = (crc32c>>24) & 0xff;
1868283808Stuexen	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
1869283808Stuexen	return htonl(crc32c);
1870283808Stuexen}
1871283808Stuexen
1872283808Stuexen/*
187318579Sfenner * Subtract 2 timeval structs:  out = out - in.
187444086Sdes * Out is assumed to be within about LONG_MAX seconds of in.
187518579Sfenner */
187618579Sfennervoid
187718579Sfennertvsub(register struct timeval *out, register struct timeval *in)
187818579Sfenner{
187918579Sfenner
188018579Sfenner	if ((out->tv_usec -= in->tv_usec) < 0)   {
188118579Sfenner		--out->tv_sec;
188218579Sfenner		out->tv_usec += 1000000;
188318579Sfenner	}
188418579Sfenner	out->tv_sec -= in->tv_sec;
188518579Sfenner}
188618579Sfenner
188718579Sfenner/*
188818579Sfenner * Construct an Internet address representation.
188918579Sfenner * If the nflag has been supplied, give
189018579Sfenner * numeric value, otherwise try for symbolic name.
189118579Sfenner */
189218579Sfennerchar *
189318579Sfennerinetname(struct in_addr in)
189418579Sfenner{
189518579Sfenner	register char *cp;
189618579Sfenner	register struct hostent *hp;
189718579Sfenner	static int first = 1;
189818579Sfenner	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
189918579Sfenner
190018579Sfenner	if (first && !nflag) {
190118579Sfenner		first = 0;
1902100787Sfenner		if (gethostname(domain, sizeof(domain) - 1) < 0)
190318579Sfenner			domain[0] = '\0';
1904100787Sfenner		else {
1905100787Sfenner			cp = strchr(domain, '.');
1906100787Sfenner			if (cp == NULL) {
1907338475Soshogbo#ifdef HAVE_LIBCASPER
1908338475Soshogbo				if (capdns != NULL)
1909338475Soshogbo					hp = cap_gethostbyname(capdns, domain);
1910338475Soshogbo				else
1911338475Soshogbo#endif
1912338475Soshogbo					hp = gethostbyname(domain);
1913100787Sfenner				if (hp != NULL)
1914100787Sfenner					cp = strchr(hp->h_name, '.');
1915100787Sfenner			}
1916100787Sfenner			if (cp == NULL)
1917100787Sfenner				domain[0] = '\0';
1918100787Sfenner			else {
1919100787Sfenner				++cp;
1920100787Sfenner				(void)strncpy(domain, cp, sizeof(domain) - 1);
1921100787Sfenner				domain[sizeof(domain) - 1] = '\0';
1922100787Sfenner			}
1923100787Sfenner		}
192418579Sfenner	}
192518579Sfenner	if (!nflag && in.s_addr != INADDR_ANY) {
1926338475Soshogbo#ifdef HAVE_LIBCASPER
1927338475Soshogbo		if (capdns != NULL)
1928338475Soshogbo			hp = cap_gethostbyaddr(capdns, (char *)&in, sizeof(in),
1929338475Soshogbo			    AF_INET);
1930338475Soshogbo		else
1931338475Soshogbo#endif
1932338475Soshogbo			hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
193318579Sfenner		if (hp != NULL) {
193418579Sfenner			if ((cp = strchr(hp->h_name, '.')) != NULL &&
193518579Sfenner			    strcmp(cp + 1, domain) == 0)
193618579Sfenner				*cp = '\0';
193718579Sfenner			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
193818579Sfenner			line[sizeof(line) - 1] = '\0';
193918579Sfenner			return (line);
194018579Sfenner		}
194118579Sfenner	}
194218579Sfenner	return (inet_ntoa(in));
194318579Sfenner}
194418579Sfenner
1945100787Sfennerstruct hostinfo *
1946100787Sfennergethostinfo(register char *hostname)
194718579Sfenner{
1948100787Sfenner	register int n;
194918579Sfenner	register struct hostent *hp;
1950100787Sfenner	register struct hostinfo *hi;
1951100787Sfenner	register char **p;
1952100787Sfenner	register u_int32_t addr, *ap;
195318579Sfenner
1954223579Sdim	if (strlen(hostname) >= MAXHOSTNAMELEN) {
1955100787Sfenner		Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1956100787Sfenner		    prog, hostname);
1957100787Sfenner		exit(1);
1958100787Sfenner	}
1959100787Sfenner	hi = calloc(1, sizeof(*hi));
1960100787Sfenner	if (hi == NULL) {
1961100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1962100787Sfenner		exit(1);
1963100787Sfenner	}
1964100787Sfenner	addr = inet_addr(hostname);
1965100787Sfenner	if ((int32_t)addr != -1) {
1966100787Sfenner		hi->name = strdup(hostname);
1967100787Sfenner		hi->n = 1;
1968100787Sfenner		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1969100787Sfenner		if (hi->addrs == NULL) {
1970100787Sfenner			Fprintf(stderr, "%s: calloc %s\n",
1971100787Sfenner			    prog, strerror(errno));
1972100787Sfenner			exit(1);
1973100787Sfenner		}
1974100787Sfenner		hi->addrs[0] = addr;
1975100787Sfenner		return (hi);
1976100787Sfenner	}
197718579Sfenner
1978338475Soshogbo#ifdef HAVE_LIBCASPER
1979338475Soshogbo	if (capdns != NULL)
1980338475Soshogbo		hp = cap_gethostbyname(capdns, hostname);
1981338475Soshogbo	else
1982338475Soshogbo#endif
1983338475Soshogbo		hp = gethostbyname(hostname);
198418579Sfenner	if (hp == NULL) {
198518579Sfenner		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
198618579Sfenner		exit(1);
198718579Sfenner	}
198818579Sfenner	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
198918579Sfenner		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
199018579Sfenner		exit(1);
199118579Sfenner	}
1992100787Sfenner	hi->name = strdup(hp->h_name);
1993100787Sfenner	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1994100787Sfenner		continue;
1995100787Sfenner	hi->n = n;
1996100787Sfenner	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1997100787Sfenner	if (hi->addrs == NULL) {
1998100787Sfenner		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1999100787Sfenner		exit(1);
2000100787Sfenner	}
2001100787Sfenner	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
2002100787Sfenner		memcpy(ap, *p, sizeof(*ap));
2003100787Sfenner	return (hi);
200418579Sfenner}
200518579Sfenner
2006100787Sfennervoid
2007100787Sfennerfreehostinfo(register struct hostinfo *hi)
200818579Sfenner{
2009100787Sfenner	if (hi->name != NULL) {
2010100787Sfenner		free(hi->name);
2011100787Sfenner		hi->name = NULL;
2012100787Sfenner	}
2013100787Sfenner	free((char *)hi->addrs);
2014100787Sfenner	free((char *)hi);
2015100787Sfenner}
201618579Sfenner
2017100787Sfennervoid
2018100787Sfennergetaddr(register u_int32_t *ap, register char *hostname)
2019100787Sfenner{
2020100787Sfenner	register struct hostinfo *hi;
2021100787Sfenner
2022100787Sfenner	hi = gethostinfo(hostname);
2023100787Sfenner	*ap = hi->addrs[0];
2024100787Sfenner	freehostinfo(hi);
2025100787Sfenner}
2026100787Sfenner
2027100787Sfennervoid
2028100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr)
2029100787Sfenner{
2030100787Sfenner
203118579Sfenner	memset(sin, 0, sizeof(*sin));
2032100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN
2033100787Sfenner	sin->sin_len = sizeof(*sin);
2034100787Sfenner#endif
203518579Sfenner	sin->sin_family = AF_INET;
2036100787Sfenner	sin->sin_addr.s_addr = addr;
203718579Sfenner}
203818579Sfenner
2039100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */
2040100787Sfennerint
2041100787Sfennerstr2val(register const char *str, register const char *what,
2042100787Sfenner    register int mi, register int ma)
204318579Sfenner{
2044100787Sfenner	register const char *cp;
2045100787Sfenner	register int val;
2046100787Sfenner	char *ep;
204718579Sfenner
2048100787Sfenner	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
2049100787Sfenner		cp = str + 2;
2050100787Sfenner		val = (int)strtol(cp, &ep, 16);
2051100787Sfenner	} else
2052100787Sfenner		val = (int)strtol(str, &ep, 10);
2053100787Sfenner	if (*ep != '\0') {
2054100787Sfenner		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
2055100787Sfenner		    prog, str, what);
205618579Sfenner		exit(1);
205718579Sfenner	}
2058100787Sfenner	if (val < mi && mi >= 0) {
2059100787Sfenner		if (mi == 0)
2060100787Sfenner			Fprintf(stderr, "%s: %s must be >= %d\n",
2061100787Sfenner			    prog, what, mi);
2062100787Sfenner		else
2063100787Sfenner			Fprintf(stderr, "%s: %s must be > %d\n",
2064100787Sfenner			    prog, what, mi - 1);
2065100787Sfenner		exit(1);
2066100787Sfenner	}
2067100787Sfenner	if (val > ma && ma >= 0) {
2068100787Sfenner		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
2069100787Sfenner		exit(1);
2070100787Sfenner	}
2071100787Sfenner	return (val);
207218579Sfenner}
207318579Sfenner
2074100787Sfennerstruct outproto *
2075100787Sfennersetproto(char *pname)
2076100787Sfenner{
2077100787Sfenner	struct outproto *proto;
2078100787Sfenner	int i;
2079100787Sfenner
2080100787Sfenner	for (i = 0; protos[i].name != NULL; i++) {
2081100787Sfenner		if (strcasecmp(protos[i].name, pname) == 0) {
2082100787Sfenner			break;
2083100787Sfenner		}
2084100787Sfenner	}
2085100787Sfenner	proto = &protos[i];
2086100787Sfenner	if (proto->name == NULL) {	/* generic handler */
2087100787Sfenner		struct protoent *pe;
2088100787Sfenner		u_long pnum;
2089100787Sfenner
2090100787Sfenner		/* Determine the IP protocol number */
2091100787Sfenner		if ((pe = getprotobyname(pname)) != NULL)
2092100787Sfenner			pnum = pe->p_proto;
2093100787Sfenner		else
2094100787Sfenner			pnum = str2val(optarg, "proto number", 1, 255);
2095100787Sfenner		proto->num = pnum;
2096100787Sfenner	}
2097100787Sfenner	return proto;
2098100787Sfenner}
2099100787Sfenner
210067682Sobrienvoid
2101163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) {
2102163387Sdwmalone	int l;
2103163387Sdwmalone	int i;
2104163387Sdwmalone
2105163387Sdwmalone	for (i = 0; i < la; i++)
2106163387Sdwmalone		Printf("%02x", (unsigned int)a[i]);
2107163387Sdwmalone	Printf("\n");
2108163387Sdwmalone	l = (la <= lb) ? la : lb;
2109163387Sdwmalone	for (i = 0; i < l; i++)
2110163387Sdwmalone		if (a[i] == b[i])
2111163387Sdwmalone			Printf("__");
2112163387Sdwmalone		else
2113163387Sdwmalone			Printf("%02x", (unsigned int)b[i]);
2114163387Sdwmalone	for (; i < lb; i++)
2115163387Sdwmalone		Printf("%02x", (unsigned int)b[i]);
2116163387Sdwmalone	Printf("\n");
2117163387Sdwmalone}
2118163387Sdwmalone
2119163387Sdwmalone
2120163387Sdwmalonevoid
212118579Sfennerusage(void)
212218579Sfenner{
212318579Sfenner	extern char version[];
212418579Sfenner
212518579Sfenner	Fprintf(stderr, "Version %s\n", version);
2126100787Sfenner	Fprintf(stderr,
2127176428Srpaulo	    "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n"
2128100787Sfenner	    "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
2129176428Srpaulo	    "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog);
213018579Sfenner	exit(1);
213118579Sfenner}
2132