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