traceroute.c revision 176428
118579Sfenner/* 2100787Sfenner * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000 318579Sfenner * The Regents of the University of California. All rights reserved. 418579Sfenner * 518579Sfenner * Redistribution and use in source and binary forms, with or without 618579Sfenner * modification, are permitted provided that: (1) source code distributions 718579Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 818579Sfenner * distributions including binary code include the above copyright notice and 918579Sfenner * this paragraph in its entirety in the documentation or other materials 1018579Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1118579Sfenner * features or use of this software display the following acknowledgement: 1218579Sfenner * ``This product includes software developed by the University of California, 1318579Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1418579Sfenner * the University nor the names of its contributors may be used to endorse 1518579Sfenner * or promote products derived from this software without specific prior 1618579Sfenner * written permission. 1718579Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1818579Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1918579Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2018579Sfenner */ 2118579Sfenner 2218579Sfenner#ifndef lint 2318579Sfennerstatic const char copyright[] = 24100787Sfenner "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\ 2518579SfennerThe Regents of the University of California. All rights reserved.\n"; 2658835Sshin#if 0 2718579Sfennerstatic const char rcsid[] = 28100787Sfenner "@(#)$Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp $ (LBL)"; 2918579Sfenner#endif 3058835Sshinstatic const char rcsid[] = 3158835Sshin "$FreeBSD: head/contrib/traceroute/traceroute.c 176428 2008-02-20 23:29:53Z rpaulo $"; 3258835Sshin#endif 3318579Sfenner 3418579Sfenner/* 3518579Sfenner * traceroute host - trace the route ip packets follow going to "host". 3618579Sfenner * 3718579Sfenner * Attempt to trace the route an ip packet would follow to some 3818579Sfenner * internet host. We find out intermediate hops by launching probe 3918579Sfenner * packets with a small ttl (time to live) then listening for an 4018579Sfenner * icmp "time exceeded" reply from a gateway. We start our probes 4118579Sfenner * with a ttl of one and increase by one until we get an icmp "port 4218579Sfenner * unreachable" (which means we got to "host") or hit a max (which 4377816Sru * defaults to net.inet.ip.ttl hops & can be changed with the -m flag). 4477816Sru * Three probes (change with -q flag) are sent at each ttl setting and 4577816Sru * a line is printed showing the ttl, address of the gateway and 4618579Sfenner * round trip time of each probe. If the probe answers come from 4718579Sfenner * different gateways, the address of each responding system will 4818579Sfenner * be printed. If there is no response within a 5 sec. timeout 4918579Sfenner * interval (changed with the -w flag), a "*" is printed for that 5018579Sfenner * probe. 5118579Sfenner * 5218579Sfenner * Probe packets are UDP format. We don't want the destination 5318579Sfenner * host to process them so the destination port is set to an 5418579Sfenner * unlikely value (if some clod on the destination is using that 5518579Sfenner * value, it can be changed with the -p flag). 5618579Sfenner * 5718579Sfenner * A sample use might be: 5818579Sfenner * 5918579Sfenner * [yak 71]% traceroute nis.nsf.net. 6077816Sru * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet 6118579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 6218579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 6318579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 6418579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 6518579Sfenner * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 6618579Sfenner * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 6718579Sfenner * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 6818579Sfenner * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 6918579Sfenner * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 7018579Sfenner * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 7118579Sfenner * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 7218579Sfenner * 7318579Sfenner * Note that lines 2 & 3 are the same. This is due to a buggy 7418579Sfenner * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 7518579Sfenner * packets with a zero ttl. 7618579Sfenner * 7718579Sfenner * A more interesting example is: 7818579Sfenner * 7918579Sfenner * [yak 72]% traceroute allspice.lcs.mit.edu. 8077816Sru * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max 8118579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 8218579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 8318579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 8418579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 8518579Sfenner * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 8618579Sfenner * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 8718579Sfenner * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 8818579Sfenner * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 8918579Sfenner * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 9018579Sfenner * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 9118579Sfenner * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 9218579Sfenner * 12 * * * 9318579Sfenner * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 9418579Sfenner * 14 * * * 9518579Sfenner * 15 * * * 9618579Sfenner * 16 * * * 9718579Sfenner * 17 * * * 9818579Sfenner * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 9918579Sfenner * 10018579Sfenner * (I start to see why I'm having so much trouble with mail to 10118579Sfenner * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 10218579Sfenner * either don't send ICMP "time exceeded" messages or send them 10318579Sfenner * with a ttl too small to reach us. 14 - 17 are running the 10418579Sfenner * MIT C Gateway code that doesn't send "time exceeded"s. God 10518579Sfenner * only knows what's going on with 12. 10618579Sfenner * 10718579Sfenner * The silent gateway 12 in the above may be the result of a bug in 10818579Sfenner * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 10918579Sfenner * sends an unreachable message using whatever ttl remains in the 11018579Sfenner * original datagram. Since, for gateways, the remaining ttl is 11118579Sfenner * zero, the icmp "time exceeded" is guaranteed to not make it back 11218579Sfenner * to us. The behavior of this bug is slightly more interesting 11318579Sfenner * when it appears on the destination system: 11418579Sfenner * 11518579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 11618579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 11718579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 11818579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 11918579Sfenner * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 12018579Sfenner * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 12118579Sfenner * 7 * * * 12218579Sfenner * 8 * * * 12318579Sfenner * 9 * * * 12418579Sfenner * 10 * * * 12518579Sfenner * 11 * * * 12618579Sfenner * 12 * * * 12718579Sfenner * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 12818579Sfenner * 12918579Sfenner * Notice that there are 12 "gateways" (13 is the final 13018579Sfenner * destination) and exactly the last half of them are "missing". 13118579Sfenner * What's really happening is that rip (a Sun-3 running Sun OS3.5) 13218579Sfenner * is using the ttl from our arriving datagram as the ttl in its 13318579Sfenner * icmp reply. So, the reply will time out on the return path 13418579Sfenner * (with no notice sent to anyone since icmp's aren't sent for 13518579Sfenner * icmp's) until we probe with a ttl that's at least twice the path 13618579Sfenner * length. I.e., rip is really only 7 hops away. A reply that 13718579Sfenner * returns with a ttl of 1 is a clue this problem exists. 13818579Sfenner * Traceroute prints a "!" after the time if the ttl is <= 1. 13918579Sfenner * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 14018579Sfenner * non-standard (HPUX) software, expect to see this problem 14118579Sfenner * frequently and/or take care picking the target host of your 14218579Sfenner * probes. 14318579Sfenner * 14418579Sfenner * Other possible annotations after the time are !H, !N, !P (got a host, 14518579Sfenner * network or protocol unreachable, respectively), !S or !F (source 14618579Sfenner * route failed or fragmentation needed -- neither of these should 14718579Sfenner * ever occur and the associated gateway is busted if you see one). If 14818579Sfenner * almost all the probes result in some kind of unreachable, traceroute 14918579Sfenner * will give up and exit. 15018579Sfenner * 15118579Sfenner * Notes 15218579Sfenner * ----- 15318579Sfenner * This program must be run by root or be setuid. (I suggest that 15418579Sfenner * you *don't* make it setuid -- casual use could result in a lot 15518579Sfenner * of unnecessary traffic on our poor, congested nets.) 15618579Sfenner * 15718579Sfenner * This program requires a kernel mod that does not appear in any 15818579Sfenner * system available from Berkeley: A raw ip socket using proto 15918579Sfenner * IPPROTO_RAW must interpret the data sent as an ip datagram (as 16018579Sfenner * opposed to data to be wrapped in a ip datagram). See the README 16118579Sfenner * file that came with the source to this program for a description 16218579Sfenner * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 16318579Sfenner * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 16418579Sfenner * MODIFIED TO RUN THIS PROGRAM. 16518579Sfenner * 16618579Sfenner * The udp port usage may appear bizarre (well, ok, it is bizarre). 16718579Sfenner * The problem is that an icmp message only contains 8 bytes of 16818579Sfenner * data from the original datagram. 8 bytes is the size of a udp 16918579Sfenner * header so, if we want to associate replies with the original 17018579Sfenner * datagram, the necessary information must be encoded into the 17118579Sfenner * udp header (the ip id could be used but there's no way to 17218579Sfenner * interlock with the kernel's assignment of ip id's and, anyway, 17318579Sfenner * it would have taken a lot more kernel hacking to allow this 17418579Sfenner * code to set the ip id). So, to allow two or more users to 17518579Sfenner * use traceroute simultaneously, we use this task's pid as the 17618579Sfenner * source port (the high bit is set to move the port number out 17718579Sfenner * of the "likely" range). To keep track of which probe is being 17818579Sfenner * replied to (so times and/or hop counts don't get confused by a 17918579Sfenner * reply that was delayed in transit), we increment the destination 18018579Sfenner * port number before each probe. 18118579Sfenner * 18218579Sfenner * Don't use this as a coding example. I was trying to find a 18318579Sfenner * routing problem and this code sort-of popped out after 48 hours 18418579Sfenner * without sleep. I was amazed it ever compiled, much less ran. 18518579Sfenner * 18618579Sfenner * I stole the idea for this program from Steve Deering. Since 18718579Sfenner * the first release, I've learned that had I attended the right 18818579Sfenner * IETF working group meetings, I also could have stolen it from Guy 18918579Sfenner * Almes or Matt Mathis. I don't know (or care) who came up with 19018579Sfenner * the idea first. I envy the originators' perspicacity and I'm 19118579Sfenner * glad they didn't keep the idea a secret. 19218579Sfenner * 19318579Sfenner * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 19418579Sfenner * enhancements to the original distribution. 19518579Sfenner * 19618579Sfenner * I've hacked up a round-trip-route version of this that works by 19718579Sfenner * sending a loose-source-routed udp datagram through the destination 19818579Sfenner * back to yourself. Unfortunately, SO many gateways botch source 19918579Sfenner * routing, the thing is almost worthless. Maybe one day... 20018579Sfenner * 20118579Sfenner * -- Van Jacobson (van@ee.lbl.gov) 20218579Sfenner * Tue Dec 20 03:50:13 PST 1988 20318579Sfenner */ 20418579Sfenner 20518579Sfenner#include <sys/param.h> 20618579Sfenner#include <sys/file.h> 20718579Sfenner#include <sys/ioctl.h> 20818579Sfenner#ifdef HAVE_SYS_SELECT_H 20918579Sfenner#include <sys/select.h> 21018579Sfenner#endif 21118579Sfenner#include <sys/socket.h> 21277816Sru#ifdef HAVE_SYS_SYSCTL_H 21377816Sru#include <sys/sysctl.h> 21477816Sru#endif 21518579Sfenner#include <sys/time.h> 21618579Sfenner 21718579Sfenner#include <netinet/in_systm.h> 21818579Sfenner#include <netinet/in.h> 21918579Sfenner#include <netinet/ip.h> 22018579Sfenner#include <netinet/ip_var.h> 22118579Sfenner#include <netinet/ip_icmp.h> 22218579Sfenner#include <netinet/udp.h> 223100787Sfenner#include <netinet/udp_var.h> 22446542Sarchie#include <netinet/tcp.h> 225100789Sfenner#include <netinet/tcpip.h> 22618579Sfenner 22718579Sfenner#include <arpa/inet.h> 22818579Sfenner 22958804Sshin#ifdef IPSEC 23058804Sshin#include <net/route.h> 231171135Sgnn#include <netipsec/ipsec.h> /* XXX */ 23258804Sshin#endif /* IPSEC */ 23358804Sshin 23418579Sfenner#include <ctype.h> 235100787Sfenner#include <err.h> 23618579Sfenner#include <errno.h> 237100787Sfenner#include <fcntl.h> 23818579Sfenner#ifdef HAVE_MALLOC_H 23918579Sfenner#include <malloc.h> 24018579Sfenner#endif 24118579Sfenner#include <memory.h> 24218579Sfenner#include <netdb.h> 24318579Sfenner#include <stdio.h> 24418579Sfenner#include <stdlib.h> 24518579Sfenner#include <string.h> 24618579Sfenner#include <unistd.h> 24718579Sfenner 24818579Sfenner#include "gnuc.h" 24918579Sfenner#ifdef HAVE_OS_PROTO_H 25018579Sfenner#include "os-proto.h" 25118579Sfenner#endif 25218579Sfenner 253100787Sfenner/* rfc1716 */ 254100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB 255100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ 256100787Sfenner#endif 257100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE 258100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ 259100787Sfenner#endif 260100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF 261100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ 262100787Sfenner#endif 263100787Sfenner 264100787Sfenner#include "findsaddr.h" 265100787Sfenner#include "ifaddrlist.h" 266176428Srpaulo#include "as.h" 267100787Sfenner#include "traceroute.h" 268100787Sfenner 26918579Sfenner/* Maximum number of gateways (include room for one noop) */ 27018579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) 27118579Sfenner 27218579Sfenner#ifndef MAXHOSTNAMELEN 27318579Sfenner#define MAXHOSTNAMELEN 64 27418579Sfenner#endif 27518579Sfenner 27618579Sfenner#define Fprintf (void)fprintf 27718579Sfenner#define Printf (void)printf 27818579Sfenner 27946542Sarchie/* What a GRE packet header looks like */ 28046542Sarchiestruct grehdr { 28146542Sarchie u_int16_t flags; 28246542Sarchie u_int16_t proto; 28346542Sarchie u_int16_t length; /* PPTP version of these fields */ 28446542Sarchie u_int16_t callId; 28546542Sarchie}; 28646542Sarchie#ifndef IPPROTO_GRE 28746542Sarchie#define IPPROTO_GRE 47 28846542Sarchie#endif 28946542Sarchie 29046542Sarchie/* For GRE, we prepare what looks like a PPTP packet */ 29146542Sarchie#define GRE_PPTP_PROTO 0x880b 29246542Sarchie 293100787Sfenner/* Host name and address list */ 294100787Sfennerstruct hostinfo { 295100787Sfenner char *name; 296100787Sfenner int n; 297100787Sfenner u_int32_t *addrs; 298100787Sfenner}; 299100787Sfenner 30018579Sfenner/* Data section of the probe packet */ 30118579Sfennerstruct outdata { 30218579Sfenner u_char seq; /* sequence number of this packet */ 30318579Sfenner u_char ttl; /* ttl packet left with */ 30418579Sfenner struct timeval tv; /* time packet left */ 30518579Sfenner}; 30618579Sfenner 307100787Sfenner#ifndef HAVE_ICMP_NEXTMTU 308100787Sfenner/* Path MTU Discovery (RFC1191) */ 309100787Sfennerstruct my_pmtu { 310100787Sfenner u_short ipm_void; 311100787Sfenner u_short ipm_nextmtu; 31246542Sarchie}; 313100787Sfenner#endif 31446542Sarchie 31518579Sfenneru_char packet[512]; /* last inbound (icmp) packet */ 31618579Sfenner 31746542Sarchiestruct ip *outip; /* last output ip packet */ 318100787Sfenneru_char *outp; /* last output inner protocol packet */ 31918579Sfenner 320163387Sdwmalonestruct ip *hip = NULL; /* Quoted IP header */ 321163387Sdwmaloneint hiplen = 0; 322163387Sdwmalone 32318579Sfenner/* loose source route gateway list (including room for final destination) */ 32418579Sfenneru_int32_t gwlist[NGATEWAYS + 1]; 32518579Sfenner 32618579Sfennerint s; /* receive (icmp) socket file descriptor */ 32718579Sfennerint sndsock; /* send (udp) socket file descriptor */ 32818579Sfenner 32918579Sfennerstruct sockaddr whereto; /* Who to try to reach */ 330100787Sfennerstruct sockaddr wherefrom; /* Who we are */ 33118579Sfennerint packlen; /* total length of packet */ 33246542Sarchieint protlen; /* length of protocol part of packet */ 333100787Sfennerint minpacket; /* min ip packet size */ 33418579Sfennerint maxpacket = 32 * 1024; /* max ip packet size */ 335100787Sfennerint pmtu; /* Path MTU Discovery (RFC1191) */ 336100787Sfenneru_int pausemsecs; 33718579Sfenner 33818579Sfennerchar *prog; 33918579Sfennerchar *source; 34018579Sfennerchar *hostname; 341100787Sfennerchar *device; 342100787Sfennerstatic const char devnull[] = "/dev/null"; 34318579Sfenner 344163387Sdwmaloneint nprobes = -1; 34577816Sruint max_ttl; 346100787Sfennerint first_ttl = 1; 34718579Sfenneru_short ident; 34846542Sarchieu_short port; /* protocol specific base "port" */ 34918579Sfenner 35018579Sfennerint options; /* socket options */ 35118579Sfennerint verbose; 35218579Sfennerint waittime = 5; /* time to wait for response (in seconds) */ 35318579Sfennerint nflag; /* print addresses numerically */ 354176428Srpauloint as_path; /* print as numbers for each hop */ 355176428Srpaulochar *as_server = NULL; 356176428Srpaulovoid *asn; 357100787Sfenner#ifdef CANT_HACK_IPCKSUM 358100787Sfennerint doipcksum = 0; /* don't calculate ip checksums by default */ 359100787Sfenner#else 360100787Sfennerint doipcksum = 1; /* calculate ip checksums by default */ 361100787Sfenner#endif 362100787Sfennerint optlen; /* length of ip options */ 363158424Scjcint fixedPort = 0; /* Use fixed destination port for TCP and UDP */ 364163387Sdwmaloneint printdiff = 0; /* Print the difference between sent and quoted */ 36518579Sfenner 36618579Sfennerextern int optind; 36718579Sfennerextern int opterr; 36818579Sfennerextern char *optarg; 36918579Sfenner 37018579Sfenner/* Forwards */ 37118579Sfennerdouble deltaT(struct timeval *, struct timeval *); 372100787Sfennervoid freehostinfo(struct hostinfo *); 373100787Sfennervoid getaddr(u_int32_t *, char *); 374100787Sfennerstruct hostinfo *gethostinfo(char *); 375100535Sfenneru_short in_cksum(u_short *, int); 37618579Sfennerchar *inetname(struct in_addr); 37718579Sfennerint main(int, char **); 378100789Sfenneru_short p_cksum(struct ip *, u_short *, int); 37918579Sfennerint packet_ok(u_char *, int, struct sockaddr_in *, int); 38018579Sfennerchar *pr_type(u_char); 38118579Sfennervoid print(u_char *, int, struct sockaddr_in *); 38258804Sshin#ifdef IPSEC 38358804Sshinint setpolicy __P((int so, char *policy)); 38458804Sshin#endif 38546542Sarchievoid send_probe(int, int); 386100787Sfennerstruct outproto *setproto(char *); 387100787Sfennerint str2val(const char *, const char *, int, int); 38818579Sfennervoid tvsub(struct timeval *, struct timeval *); 38967682Sobrienvoid usage(void); 390100787Sfennerint wait_for_reply(int, struct sockaddr_in *, const struct timeval *); 391163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int); 392100787Sfenner#ifndef HAVE_USLEEP 393100787Sfennerint usleep(u_int); 394100787Sfenner#endif 39518579Sfenner 39646542Sarchievoid udp_prep(struct outdata *); 39746542Sarchieint udp_check(const u_char *, int); 39846542Sarchievoid tcp_prep(struct outdata *); 39946542Sarchieint tcp_check(const u_char *, int); 40046542Sarchievoid gre_prep(struct outdata *); 40146542Sarchieint gre_check(const u_char *, int); 40246542Sarchievoid gen_prep(struct outdata *); 40346542Sarchieint gen_check(const u_char *, int); 404100535Sfennervoid icmp_prep(struct outdata *); 405100535Sfennerint icmp_check(const u_char *, int); 40646542Sarchie 407100787Sfenner/* Descriptor structure for each outgoing protocol we support */ 408100787Sfennerstruct outproto { 409100787Sfenner char *name; /* name of protocol */ 410163387Sdwmalone const char *key; /* An ascii key for the bytes of the header */ 411100787Sfenner u_char num; /* IP protocol number */ 412100787Sfenner u_short hdrlen; /* max size of protocol header */ 413100787Sfenner u_short port; /* default base protocol-specific "port" */ 414100787Sfenner void (*prepare)(struct outdata *); 415100787Sfenner /* finish preparing an outgoing packet */ 416100787Sfenner int (*check)(const u_char *, int); 417100787Sfenner /* check an incoming packet */ 418100787Sfenner}; 419100787Sfenner 42046542Sarchie/* List of supported protocols. The first one is the default. The last 42146542Sarchie one is the handler for generic protocols not explicitly listed. */ 42246542Sarchiestruct outproto protos[] = { 42346542Sarchie { 42446542Sarchie "udp", 425163387Sdwmalone "spt dpt len sum", 42646542Sarchie IPPROTO_UDP, 42746542Sarchie sizeof(struct udphdr), 42846542Sarchie 32768 + 666, 42946542Sarchie udp_prep, 43046542Sarchie udp_check 43146542Sarchie }, 43246542Sarchie { 43346542Sarchie "tcp", 434163387Sdwmalone "spt dpt seq ack xxflwin sum urp", 43546542Sarchie IPPROTO_TCP, 43646542Sarchie sizeof(struct tcphdr), 43746542Sarchie 32768 + 666, 43846542Sarchie tcp_prep, 43946542Sarchie tcp_check 44046542Sarchie }, 44146542Sarchie { 44246542Sarchie "gre", 443163387Sdwmalone "flg pro len clid", 44446542Sarchie IPPROTO_GRE, 44546542Sarchie sizeof(struct grehdr), 44646542Sarchie GRE_PPTP_PROTO, 44746542Sarchie gre_prep, 44846542Sarchie gre_check 44946542Sarchie }, 45046542Sarchie { 451100535Sfenner "icmp", 452163387Sdwmalone "typ cod sum ", 453100535Sfenner IPPROTO_ICMP, 454100535Sfenner sizeof(struct icmp), 455100535Sfenner 0, 456100535Sfenner icmp_prep, 457100535Sfenner icmp_check 458100535Sfenner }, 459100535Sfenner { 46046542Sarchie NULL, 461163387Sdwmalone NULL, 46246542Sarchie 0, 46346542Sarchie 2 * sizeof(u_short), 46446542Sarchie 0, 46546542Sarchie gen_prep, 46646542Sarchie gen_check 46746542Sarchie }, 46846542Sarchie}; 46946542Sarchiestruct outproto *proto = &protos[0]; 47046542Sarchie 471163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts"; 472163387Sdwmalone 47318579Sfennerint 47418579Sfennermain(int argc, char **argv) 47518579Sfenner{ 476100787Sfenner register int op, code, n; 47718579Sfenner register char *cp; 478100787Sfenner register const char *err; 479100787Sfenner register u_int32_t *ap; 480100787Sfenner register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; 48118579Sfenner register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; 482100787Sfenner register struct hostinfo *hi; 48318579Sfenner int on = 1; 48418579Sfenner register struct protoent *pe; 48518579Sfenner register int ttl, probe, i; 48618579Sfenner register int seq = 0; 487100787Sfenner int tos = 0, settos = 0; 48818579Sfenner register int lsrr = 0; 489100787Sfenner register u_short off = 0; 490100787Sfenner struct ifaddrlist *al; 491100787Sfenner char errbuf[132]; 49248221Sarchie int requestPort = -1; 49318803Ssef int sump = 0; 49418583Sfenner int sockerrno; 49518579Sfenner 496100787Sfenner /* Insure the socket fds won't be 0, 1 or 2 */ 497100787Sfenner if (open(devnull, O_RDONLY) < 0 || 498100787Sfenner open(devnull, O_RDONLY) < 0 || 499100787Sfenner open(devnull, O_RDONLY) < 0) { 500100787Sfenner Fprintf(stderr, "%s: open \"%s\": %s\n", 501100787Sfenner prog, devnull, strerror(errno)); 502100787Sfenner exit(1); 503100787Sfenner } 50418583Sfenner /* 50518583Sfenner * Do the setuid-required stuff first, then lose priveleges ASAP. 50618583Sfenner * Do error checking for these two calls where they appeared in 50718583Sfenner * the original code. 50818583Sfenner */ 50918583Sfenner cp = "icmp"; 51018583Sfenner pe = getprotobyname(cp); 51118583Sfenner if (pe) { 51218583Sfenner if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) 51318583Sfenner sockerrno = errno; 51418583Sfenner else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 51518583Sfenner sockerrno = errno; 51618583Sfenner } 51718583Sfenner 51818583Sfenner setuid(getuid()); 51918583Sfenner 52077816Sru#ifdef IPCTL_DEFTTL 52177816Sru { 52277816Sru int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; 52377816Sru size_t sz = sizeof(max_ttl); 52477816Sru 525100787Sfenner if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) { 526100787Sfenner perror("sysctl(net.inet.ip.ttl)"); 527100787Sfenner exit(1); 528100787Sfenner } 52977816Sru } 53077816Sru#else 53177816Sru max_ttl = 30; 53277816Sru#endif 53377816Sru 534100787Sfenner if (argv[0] == NULL) 535100787Sfenner prog = "traceroute"; 536100787Sfenner else if ((cp = strrchr(argv[0], '/')) != NULL) 53718579Sfenner prog = cp + 1; 53818579Sfenner else 53918579Sfenner prog = argv[0]; 54018579Sfenner 54118579Sfenner opterr = 0; 542176428Srpaulo while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF) 54318579Sfenner switch (op) { 544176428Srpaulo case 'a': 545176428Srpaulo as_path = 1; 546176428Srpaulo break; 547176428Srpaulo 548176428Srpaulo case 'A': 549176428Srpaulo as_path = 1; 550176428Srpaulo as_server = optarg; 551176428Srpaulo break; 552176428Srpaulo 55318579Sfenner case 'd': 55418579Sfenner options |= SO_DEBUG; 55518579Sfenner break; 55618579Sfenner 557163387Sdwmalone case 'D': 558163387Sdwmalone printdiff = 1; 559163387Sdwmalone break; 560163387Sdwmalone 561158424Scjc case 'e': 562158424Scjc fixedPort = 1; 563158424Scjc break; 564158424Scjc 565100787Sfenner case 'f': 566100787Sfenner case 'M': /* FreeBSD compat. */ 567100787Sfenner first_ttl = str2val(optarg, "first ttl", 1, 255); 568100787Sfenner break; 569100787Sfenner 570100787Sfenner case 'F': 571100787Sfenner off = IP_DF; 572100787Sfenner break; 573100787Sfenner 57418579Sfenner case 'g': 57518579Sfenner if (lsrr >= NGATEWAYS) { 57618579Sfenner Fprintf(stderr, 57718579Sfenner "%s: No more than %d gateways\n", 57818579Sfenner prog, NGATEWAYS); 57918579Sfenner exit(1); 58018579Sfenner } 581100787Sfenner getaddr(gwlist + lsrr, optarg); 58218579Sfenner ++lsrr; 58318579Sfenner break; 58418579Sfenner 585100787Sfenner case 'i': 586100787Sfenner device = optarg; 58747071Sarchie break; 58847071Sarchie 589100787Sfenner case 'I': 590100787Sfenner proto = setproto("icmp"); 591100787Sfenner break; 592100787Sfenner 59318579Sfenner case 'm': 594100787Sfenner max_ttl = str2val(optarg, "max ttl", 1, 255); 59518579Sfenner break; 59618579Sfenner 59718579Sfenner case 'n': 59818579Sfenner ++nflag; 59918579Sfenner break; 60018579Sfenner 60146542Sarchie case 'P': 602100787Sfenner proto = setproto(optarg); 60346542Sarchie break; 60446542Sarchie 60518579Sfenner case 'p': 606100787Sfenner requestPort = (u_short)str2val(optarg, "port", 607100787Sfenner 1, (1 << 16) - 1); 60818579Sfenner break; 60918579Sfenner 61018579Sfenner case 'q': 611100787Sfenner nprobes = str2val(optarg, "nprobes", 1, -1); 61218579Sfenner break; 61318579Sfenner 61418579Sfenner case 'r': 61518579Sfenner options |= SO_DONTROUTE; 61618579Sfenner break; 61718579Sfenner 61818579Sfenner case 's': 61918579Sfenner /* 62018579Sfenner * set the ip source address of the outbound 62118579Sfenner * probe (e.g., on a multi-homed host). 62218579Sfenner */ 62318579Sfenner source = optarg; 62418579Sfenner break; 62518579Sfenner 626100787Sfenner case 'S': 627100787Sfenner sump = 1; 628100787Sfenner break; 629100787Sfenner 63018579Sfenner case 't': 631100787Sfenner tos = str2val(optarg, "tos", 0, 255); 632100787Sfenner ++settos; 63318579Sfenner break; 63418579Sfenner 63518579Sfenner case 'v': 63618579Sfenner ++verbose; 63718579Sfenner break; 63818579Sfenner 639100787Sfenner case 'x': 640100787Sfenner doipcksum = (doipcksum == 0); 641100787Sfenner break; 642100787Sfenner 64318579Sfenner case 'w': 644100787Sfenner waittime = str2val(optarg, "wait time", 645169144Smaxim 1, 24 * 60 * 60); 64618579Sfenner break; 64718579Sfenner 648100787Sfenner case 'z': 649100787Sfenner pausemsecs = str2val(optarg, "pause msecs", 650100787Sfenner 0, 60 * 60 * 1000); 651100787Sfenner break; 652100787Sfenner 65318579Sfenner default: 65418579Sfenner usage(); 65518579Sfenner } 65618579Sfenner 65748221Sarchie /* Set requested port, if any, else default for this protocol */ 65848221Sarchie port = (requestPort != -1) ? requestPort : proto->port; 65948221Sarchie 660163387Sdwmalone if (nprobes == -1) 661163387Sdwmalone nprobes = printdiff ? 1 : 3; 662163387Sdwmalone 663100787Sfenner if (first_ttl > max_ttl) { 664100787Sfenner Fprintf(stderr, 665100787Sfenner "%s: first ttl (%d) may not be greater than max ttl (%d)\n", 666100787Sfenner prog, first_ttl, max_ttl); 66747071Sarchie exit(1); 66847071Sarchie } 66947071Sarchie 670100787Sfenner if (!doipcksum) 671100787Sfenner Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog); 672100787Sfenner 673100787Sfenner if (lsrr > 0) 674100787Sfenner optlen = (lsrr + 1) * sizeof(gwlist[0]); 675100787Sfenner minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen; 676100787Sfenner packlen = minpacket; /* minimum sized packet */ 677100787Sfenner 67818579Sfenner /* Process destination and optional packet size */ 67918579Sfenner switch (argc - optind) { 68018579Sfenner 68118579Sfenner case 2: 682100787Sfenner packlen = str2val(argv[optind + 1], 683100787Sfenner "packet length", minpacket, maxpacket); 684100787Sfenner /* Fall through */ 68518579Sfenner 68618579Sfenner case 1: 687100787Sfenner hostname = argv[optind]; 688100787Sfenner hi = gethostinfo(hostname); 689100787Sfenner setsin(to, hi->addrs[0]); 690100787Sfenner if (hi->n > 1) 691100787Sfenner Fprintf(stderr, 692100787Sfenner "%s: Warning: %s has multiple addresses; using %s\n", 693100787Sfenner prog, hostname, inet_ntoa(to->sin_addr)); 694100787Sfenner hostname = hi->name; 695100787Sfenner hi->name = NULL; 696100787Sfenner freehostinfo(hi); 69718579Sfenner break; 69818579Sfenner 69918579Sfenner default: 70018579Sfenner usage(); 70118579Sfenner } 70218579Sfenner 70318579Sfenner#ifdef HAVE_SETLINEBUF 70418579Sfenner setlinebuf (stdout); 70518579Sfenner#else 70618579Sfenner setvbuf(stdout, NULL, _IOLBF, 0); 70718579Sfenner#endif 70818579Sfenner 70946542Sarchie protlen = packlen - sizeof(*outip) - optlen; 71018579Sfenner 71118579Sfenner outip = (struct ip *)malloc((unsigned)packlen); 71218579Sfenner if (outip == NULL) { 71318579Sfenner Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); 71418579Sfenner exit(1); 71518579Sfenner } 71618579Sfenner memset((char *)outip, 0, packlen); 71718579Sfenner 71818579Sfenner outip->ip_v = IPVERSION; 719100787Sfenner if (settos) 720100787Sfenner outip->ip_tos = tos; 721100787Sfenner#ifdef BYTESWAP_IP_HDR 72218579Sfenner outip->ip_len = htons(packlen); 723100787Sfenner outip->ip_off = htons(off); 72418579Sfenner#else 72518579Sfenner outip->ip_len = packlen; 726100787Sfenner outip->ip_off = off; 72718579Sfenner#endif 72846542Sarchie outip->ip_p = proto->num; 729100787Sfenner outp = (u_char *)(outip + 1); 73018579Sfenner#ifdef HAVE_RAW_OPTIONS 73118579Sfenner if (lsrr > 0) { 73218579Sfenner register u_char *optlist; 73318579Sfenner 734100787Sfenner optlist = outp; 735100787Sfenner outp += optlen; 73618579Sfenner 73718579Sfenner /* final hop */ 73818579Sfenner gwlist[lsrr] = to->sin_addr.s_addr; 73918579Sfenner 74018579Sfenner outip->ip_dst.s_addr = gwlist[0]; 74118579Sfenner 74218579Sfenner /* force 4 byte alignment */ 74318579Sfenner optlist[0] = IPOPT_NOP; 74418579Sfenner /* loose source route option */ 74518579Sfenner optlist[1] = IPOPT_LSRR; 74618579Sfenner i = lsrr * sizeof(gwlist[0]); 74718579Sfenner optlist[2] = i + 3; 74818579Sfenner /* Pointer to LSRR addresses */ 74918579Sfenner optlist[3] = IPOPT_MINOFF; 75018579Sfenner memcpy(optlist + 4, gwlist + 1, i); 75118579Sfenner } else 75218579Sfenner#endif 75318579Sfenner outip->ip_dst = to->sin_addr; 75418579Sfenner 755100787Sfenner outip->ip_hl = (outp - (u_char *)outip) >> 2; 75618579Sfenner ident = (getpid() & 0xffff) | 0x8000; 75718579Sfenner 75818583Sfenner if (pe == NULL) { 75918579Sfenner Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 76018579Sfenner exit(1); 76118579Sfenner } 76218583Sfenner if (s < 0) { 76318583Sfenner errno = sockerrno; 76418579Sfenner Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); 76518579Sfenner exit(1); 76618579Sfenner } 76718579Sfenner if (options & SO_DEBUG) 76818579Sfenner (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, 76918579Sfenner sizeof(on)); 77018579Sfenner if (options & SO_DONTROUTE) 77118579Sfenner (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 77218579Sfenner sizeof(on)); 77318579Sfenner 77458804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 77558804Sshin if (setpolicy(s, "in bypass") < 0) 77666809Skris errx(1, "%s", ipsec_strerror()); 77758804Sshin 77858804Sshin if (setpolicy(s, "out bypass") < 0) 77966809Skris errx(1, "%s", ipsec_strerror()); 78058804Sshin#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ 78158804Sshin 78218583Sfenner if (sndsock < 0) { 78318583Sfenner errno = sockerrno; 78418579Sfenner Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); 78518579Sfenner exit(1); 78618579Sfenner } 78718579Sfenner 78818579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) 78918579Sfenner if (lsrr > 0) { 79018579Sfenner u_char optlist[MAX_IPOPTLEN]; 79118579Sfenner 79218579Sfenner cp = "ip"; 79318579Sfenner if ((pe = getprotobyname(cp)) == NULL) { 79418579Sfenner Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 79518579Sfenner exit(1); 79618579Sfenner } 79718579Sfenner 79818579Sfenner /* final hop */ 79918579Sfenner gwlist[lsrr] = to->sin_addr.s_addr; 80018579Sfenner ++lsrr; 80118579Sfenner 80218579Sfenner /* force 4 byte alignment */ 80318579Sfenner optlist[0] = IPOPT_NOP; 80418579Sfenner /* loose source route option */ 80518579Sfenner optlist[1] = IPOPT_LSRR; 80618579Sfenner i = lsrr * sizeof(gwlist[0]); 80718579Sfenner optlist[2] = i + 3; 80818579Sfenner /* Pointer to LSRR addresses */ 80918579Sfenner optlist[3] = IPOPT_MINOFF; 81018579Sfenner memcpy(optlist + 4, gwlist, i); 81118579Sfenner 812100787Sfenner if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, 813100787Sfenner (char *)optlist, i + sizeof(gwlist[0]))) < 0) { 81418579Sfenner Fprintf(stderr, "%s: IP_OPTIONS: %s\n", 81518579Sfenner prog, strerror(errno)); 81618579Sfenner exit(1); 81718579Sfenner } 81818579Sfenner } 81918579Sfenner#endif 82018579Sfenner 82118579Sfenner#ifdef SO_SNDBUF 82218579Sfenner if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, 82318579Sfenner sizeof(packlen)) < 0) { 82418579Sfenner Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno)); 82518579Sfenner exit(1); 82618579Sfenner } 82718579Sfenner#endif 82818579Sfenner#ifdef IP_HDRINCL 82918579Sfenner if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 83018579Sfenner sizeof(on)) < 0) { 83118579Sfenner Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); 83218579Sfenner exit(1); 83318579Sfenner } 834100787Sfenner#else 835100787Sfenner#ifdef IP_TOS 836100787Sfenner if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, 837100787Sfenner (char *)&tos, sizeof(tos)) < 0) { 838100787Sfenner Fprintf(stderr, "%s: setsockopt tos %d: %s\n", 839100787Sfenner prog, tos, strerror(errno)); 840100787Sfenner exit(1); 841100787Sfenner } 84218579Sfenner#endif 843100787Sfenner#endif 84418579Sfenner if (options & SO_DEBUG) 84518579Sfenner (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, 84618579Sfenner sizeof(on)); 84718579Sfenner if (options & SO_DONTROUTE) 84818579Sfenner (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 84918579Sfenner sizeof(on)); 85018579Sfenner 851100787Sfenner /* Get the interface address list */ 852100787Sfenner n = ifaddrlist(&al, errbuf); 853100787Sfenner if (n < 0) { 854100787Sfenner Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); 855100787Sfenner exit(1); 856100787Sfenner } 857100787Sfenner if (n == 0) { 858100787Sfenner Fprintf(stderr, 859100787Sfenner "%s: Can't find any network interfaces\n", prog); 860100787Sfenner exit(1); 861100787Sfenner } 862100787Sfenner 863100787Sfenner /* Look for a specific device */ 864100787Sfenner if (device != NULL) { 865100787Sfenner for (i = n; i > 0; --i, ++al) 866100787Sfenner if (strcmp(device, al->device) == 0) 867100787Sfenner break; 868100787Sfenner if (i <= 0) { 869100787Sfenner Fprintf(stderr, "%s: Can't find interface %.32s\n", 870100787Sfenner prog, device); 871100787Sfenner exit(1); 87218579Sfenner } 87318579Sfenner } 87418579Sfenner 875100787Sfenner /* Determine our source address */ 876100787Sfenner if (source == NULL) { 877100787Sfenner /* 878100787Sfenner * If a device was specified, use the interface address. 879100787Sfenner * Otherwise, try to determine our source address. 880100787Sfenner */ 881100787Sfenner if (device != NULL) 882100787Sfenner setsin(from, al->addr); 883100787Sfenner else if ((err = findsaddr(to, from)) != NULL) { 884100787Sfenner Fprintf(stderr, "%s: findsaddr: %s\n", 885100787Sfenner prog, err); 886100787Sfenner exit(1); 887100787Sfenner } 888100787Sfenner } else { 889100787Sfenner hi = gethostinfo(source); 890100787Sfenner source = hi->name; 891100787Sfenner hi->name = NULL; 892100787Sfenner /* 893100787Sfenner * If the device was specified make sure it 894100787Sfenner * corresponds to the source address specified. 895100787Sfenner * Otherwise, use the first address (and warn if 896100787Sfenner * there are more than one). 897100787Sfenner */ 898100787Sfenner if (device != NULL) { 899100787Sfenner for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) 900100787Sfenner if (*ap == al->addr) 901100787Sfenner break; 902100787Sfenner if (i <= 0) { 903100787Sfenner Fprintf(stderr, 904100787Sfenner "%s: %s is not on interface %.32s\n", 905100787Sfenner prog, source, device); 906100787Sfenner exit(1); 907100787Sfenner } 908100787Sfenner setsin(from, *ap); 909100787Sfenner } else { 910100787Sfenner setsin(from, hi->addrs[0]); 911100787Sfenner if (hi->n > 1) 912100787Sfenner Fprintf(stderr, 913100787Sfenner "%s: Warning: %s has multiple addresses; using %s\n", 914100787Sfenner prog, source, inet_ntoa(from->sin_addr)); 915100787Sfenner } 916100787Sfenner freehostinfo(hi); 917100787Sfenner } 918100787Sfenner 919100787Sfenner outip->ip_src = from->sin_addr; 920128365Spb 921128365Spb /* Check the source address (-s), if any, is valid */ 922100787Sfenner if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { 923100787Sfenner Fprintf(stderr, "%s: bind: %s\n", 924100787Sfenner prog, strerror(errno)); 925100787Sfenner exit (1); 926100787Sfenner } 927100787Sfenner 928176428Srpaulo if (as_path) { 929176428Srpaulo asn = as_setup(as_server); 930176428Srpaulo if (asn == NULL) { 931176428Srpaulo Fprintf(stderr, "%s: as_setup failed, AS# lookups" 932176428Srpaulo " disabled\n", prog); 933176428Srpaulo (void)fflush(stderr); 934176428Srpaulo as_path = 0; 935176428Srpaulo } 936176428Srpaulo } 937176428Srpaulo 93858804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 93958804Sshin if (setpolicy(sndsock, "in bypass") < 0) 94066809Skris errx(1, "%s", ipsec_strerror()); 94158804Sshin 94258804Sshin if (setpolicy(sndsock, "out bypass") < 0) 94366809Skris errx(1, "%s", ipsec_strerror()); 94458804Sshin#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ 94558804Sshin 94618579Sfenner Fprintf(stderr, "%s to %s (%s)", 94718579Sfenner prog, hostname, inet_ntoa(to->sin_addr)); 94818579Sfenner if (source) 94918579Sfenner Fprintf(stderr, " from %s", source); 95018579Sfenner Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); 95118579Sfenner (void)fflush(stderr); 95218579Sfenner 953100787Sfenner for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 95418579Sfenner u_int32_t lastaddr = 0; 955100787Sfenner int gotlastaddr = 0; 95618579Sfenner int got_there = 0; 95718579Sfenner int unreachable = 0; 958100787Sfenner int sentfirst = 0; 95918695Ssef int loss; 96018579Sfenner 96118579Sfenner Printf("%2d ", ttl); 96218695Ssef for (probe = 0, loss = 0; probe < nprobes; ++probe) { 96318579Sfenner register int cc; 96418579Sfenner struct timeval t1, t2; 96518579Sfenner struct timezone tz; 96618579Sfenner register struct ip *ip; 96746542Sarchie struct outdata outdata; 96818579Sfenner 969100787Sfenner if (sentfirst && pausemsecs > 0) 970100787Sfenner usleep(pausemsecs * 1000); 97146542Sarchie /* Prepare outgoing data */ 97246542Sarchie outdata.seq = ++seq; 97346542Sarchie outdata.ttl = ttl; 97446542Sarchie 97546542Sarchie /* Avoid alignment problems by copying bytewise: */ 97618579Sfenner (void)gettimeofday(&t1, &tz); 97746542Sarchie memcpy(&outdata.tv, &t1, sizeof(outdata.tv)); 97846542Sarchie 97946542Sarchie /* Finalize and send packet */ 98046542Sarchie (*proto->prepare)(&outdata); 98146542Sarchie send_probe(seq, ttl); 982100787Sfenner ++sentfirst; 98346542Sarchie 98446542Sarchie /* Wait for a reply */ 985100787Sfenner while ((cc = wait_for_reply(s, from, &t1)) != 0) { 98618583Sfenner double T; 98718583Sfenner int precis; 98818583Sfenner 98918579Sfenner (void)gettimeofday(&t2, &tz); 990100787Sfenner i = packet_ok(packet, cc, from, seq); 99118579Sfenner /* Skip short packet */ 99218579Sfenner if (i == 0) 99318579Sfenner continue; 994100787Sfenner if (!gotlastaddr || 995100787Sfenner from->sin_addr.s_addr != lastaddr) { 996154192Spav if (gotlastaddr) printf("\n "); 997100787Sfenner print(packet, cc, from); 998100787Sfenner lastaddr = from->sin_addr.s_addr; 999100787Sfenner ++gotlastaddr; 100018579Sfenner } 100118583Sfenner T = deltaT(&t1, &t2); 100218583Sfenner#ifdef SANE_PRECISION 100318583Sfenner if (T >= 1000.0) 100418583Sfenner precis = 0; 100518583Sfenner else if (T >= 100.0) 100618583Sfenner precis = 1; 100718583Sfenner else if (T >= 10.0) 100818583Sfenner precis = 2; 100918583Sfenner else 101018583Sfenner#endif 101118583Sfenner precis = 3; 101218583Sfenner Printf(" %.*f ms", precis, T); 1013163387Sdwmalone if (printdiff) { 1014163387Sdwmalone Printf("\n"); 1015163387Sdwmalone Printf("%*.*s%s\n", 1016163387Sdwmalone -(outip->ip_hl << 3), 1017163387Sdwmalone outip->ip_hl << 3, 1018163387Sdwmalone ip_hdr_key, 1019163387Sdwmalone proto->key); 1020163387Sdwmalone pkt_compare((void *)outip, packlen, 1021163387Sdwmalone (void *)hip, hiplen); 1022163387Sdwmalone } 1023100535Sfenner if (i == -2) { 1024100567Sdcs#ifndef ARCHAIC 1025100535Sfenner ip = (struct ip *)packet; 1026100535Sfenner if (ip->ip_ttl <= 1) 1027100535Sfenner Printf(" !"); 1028100535Sfenner#endif 1029100535Sfenner ++got_there; 1030100535Sfenner break; 1031100535Sfenner } 103218579Sfenner /* time exceeded in transit */ 103318579Sfenner if (i == -1) 103418579Sfenner break; 103518579Sfenner code = i - 1; 103618579Sfenner switch (code) { 103718579Sfenner 103818579Sfenner case ICMP_UNREACH_PORT: 103918579Sfenner#ifndef ARCHAIC 104018579Sfenner ip = (struct ip *)packet; 104118579Sfenner if (ip->ip_ttl <= 1) 104218579Sfenner Printf(" !"); 104318579Sfenner#endif 104418579Sfenner ++got_there; 104518579Sfenner break; 104618579Sfenner 104718579Sfenner case ICMP_UNREACH_NET: 104818579Sfenner ++unreachable; 104918579Sfenner Printf(" !N"); 105018579Sfenner break; 105118579Sfenner 105218579Sfenner case ICMP_UNREACH_HOST: 105318579Sfenner ++unreachable; 105418579Sfenner Printf(" !H"); 105518579Sfenner break; 105618579Sfenner 105718579Sfenner case ICMP_UNREACH_PROTOCOL: 105818579Sfenner ++got_there; 105918579Sfenner Printf(" !P"); 106018579Sfenner break; 106118579Sfenner 106218579Sfenner case ICMP_UNREACH_NEEDFRAG: 106318579Sfenner ++unreachable; 1064100787Sfenner Printf(" !F-%d", pmtu); 106518579Sfenner break; 106618579Sfenner 106718579Sfenner case ICMP_UNREACH_SRCFAIL: 106818579Sfenner ++unreachable; 106918579Sfenner Printf(" !S"); 107018579Sfenner break; 107118579Sfenner 1072159576Sdwmalone case ICMP_UNREACH_NET_UNKNOWN: 1073159576Sdwmalone ++unreachable; 1074159576Sdwmalone Printf(" !U"); 1075159576Sdwmalone break; 1076159576Sdwmalone 1077159576Sdwmalone case ICMP_UNREACH_HOST_UNKNOWN: 1078159576Sdwmalone ++unreachable; 1079159576Sdwmalone Printf(" !W"); 1080159576Sdwmalone break; 1081159576Sdwmalone 1082159576Sdwmalone case ICMP_UNREACH_ISOLATED: 1083159576Sdwmalone ++unreachable; 1084159576Sdwmalone Printf(" !I"); 1085159576Sdwmalone break; 1086159576Sdwmalone 1087159576Sdwmalone case ICMP_UNREACH_NET_PROHIB: 1088159576Sdwmalone ++unreachable; 1089159576Sdwmalone Printf(" !A"); 1090159576Sdwmalone break; 1091159576Sdwmalone 1092159576Sdwmalone case ICMP_UNREACH_HOST_PROHIB: 1093159576Sdwmalone ++unreachable; 1094159576Sdwmalone Printf(" !Z"); 1095159576Sdwmalone break; 1096159576Sdwmalone 1097159576Sdwmalone case ICMP_UNREACH_TOSNET: 1098159576Sdwmalone ++unreachable; 1099159576Sdwmalone Printf(" !Q"); 1100159576Sdwmalone break; 1101159576Sdwmalone 1102159576Sdwmalone case ICMP_UNREACH_TOSHOST: 1103159576Sdwmalone ++unreachable; 1104159576Sdwmalone Printf(" !T"); 1105159576Sdwmalone break; 1106159576Sdwmalone 110718579Sfenner case ICMP_UNREACH_FILTER_PROHIB: 110818579Sfenner ++unreachable; 110918579Sfenner Printf(" !X"); 111018579Sfenner break; 111118579Sfenner 1112100787Sfenner case ICMP_UNREACH_HOST_PRECEDENCE: 1113100787Sfenner ++unreachable; 1114100787Sfenner Printf(" !V"); 1115100787Sfenner break; 1116100787Sfenner 1117100787Sfenner case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1118100787Sfenner ++unreachable; 1119100787Sfenner Printf(" !C"); 1120100787Sfenner break; 1121100787Sfenner 112218579Sfenner default: 112318579Sfenner ++unreachable; 112418579Sfenner Printf(" !<%d>", code); 112518579Sfenner break; 112618579Sfenner } 112718579Sfenner break; 112818579Sfenner } 112918695Ssef if (cc == 0) { 113018695Ssef loss++; 113118579Sfenner Printf(" *"); 113218695Ssef } 113318579Sfenner (void)fflush(stdout); 113418579Sfenner } 113518803Ssef if (sump) { 113618811Ssef Printf(" (%d%% loss)", (loss * 100) / nprobes); 113718803Ssef } 113818579Sfenner putchar('\n'); 113918579Sfenner if (got_there || 114018579Sfenner (unreachable > 0 && unreachable >= nprobes - 1)) 114118579Sfenner break; 114218579Sfenner } 1143176428Srpaulo if (as_path) 1144176428Srpaulo as_shutdown(asn); 114518579Sfenner exit(0); 114618579Sfenner} 114718579Sfenner 114818579Sfennerint 114918579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp, 1150100787Sfenner register const struct timeval *tp) 115118579Sfenner{ 115266810Skris fd_set *fdsp; 115366810Skris size_t nfds; 115418579Sfenner struct timeval now, wait; 115518579Sfenner struct timezone tz; 115618579Sfenner register int cc = 0; 115744086Sdes register int error; 115818579Sfenner int fromlen = sizeof(*fromp); 115918579Sfenner 116066810Skris nfds = howmany(sock + 1, NFDBITS); 116198709Srobert if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL) 116266810Skris err(1, "malloc"); 116398709Srobert memset(fdsp, 0, nfds * sizeof(fd_mask)); 116466810Skris FD_SET(sock, fdsp); 116518579Sfenner 116618579Sfenner wait.tv_sec = tp->tv_sec + waittime; 116718579Sfenner wait.tv_usec = tp->tv_usec; 116818579Sfenner (void)gettimeofday(&now, &tz); 116918579Sfenner tvsub(&wait, &now); 117044086Sdes if (wait.tv_sec < 0) { 117144086Sdes wait.tv_sec = 0; 117244086Sdes wait.tv_usec = 1; 117344086Sdes } 117418579Sfenner 117566810Skris error = select(sock + 1, fdsp, NULL, NULL, &wait); 117644086Sdes if (error == -1 && errno == EINVAL) { 117744086Sdes Fprintf(stderr, "%s: botched select() args\n", prog); 117844086Sdes exit(1); 117944086Sdes } 118044086Sdes if (error > 0) 1181100787Sfenner cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, 118218579Sfenner (struct sockaddr *)fromp, &fromlen); 118318579Sfenner 118466810Skris free(fdsp); 118518579Sfenner return(cc); 118618579Sfenner} 118718579Sfenner 1188100787Sfennervoid 1189100787Sfennersend_probe(int seq, int ttl) 1190100787Sfenner{ 1191100787Sfenner register int cc; 1192100787Sfenner 1193100787Sfenner outip->ip_ttl = ttl; 1194100787Sfenner outip->ip_id = htons(ident + seq); 1195100787Sfenner 1196100787Sfenner /* XXX undocumented debugging hack */ 1197100787Sfenner if (verbose > 1) { 1198100787Sfenner register const u_short *sp; 1199100787Sfenner register int nshorts, i; 1200100787Sfenner 1201100787Sfenner sp = (u_short *)outip; 1202100787Sfenner nshorts = (u_int)packlen / sizeof(u_short); 1203100787Sfenner i = 0; 1204100787Sfenner Printf("[ %d bytes", packlen); 1205100787Sfenner while (--nshorts >= 0) { 1206100787Sfenner if ((i++ % 8) == 0) 1207100787Sfenner Printf("\n\t"); 1208100787Sfenner Printf(" %04x", ntohs(*sp++)); 1209100787Sfenner } 1210100787Sfenner if (packlen & 1) { 1211100787Sfenner if ((i % 8) == 0) 1212100787Sfenner Printf("\n\t"); 1213100787Sfenner Printf(" %02x", *(u_char *)sp); 1214100787Sfenner } 1215100787Sfenner Printf("]\n"); 1216100787Sfenner } 1217100787Sfenner 1218100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL) 1219100787Sfenner if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, 1220100787Sfenner (char *)&ttl, sizeof(ttl)) < 0) { 1221100787Sfenner Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", 1222100787Sfenner prog, ttl, strerror(errno)); 1223100787Sfenner exit(1); 1224100787Sfenner } 1225100787Sfenner#endif 1226100787Sfenner 1227100787Sfenner cc = sendto(sndsock, (char *)outip, 1228100787Sfenner packlen, 0, &whereto, sizeof(whereto)); 1229100787Sfenner if (cc < 0 || cc != packlen) { 1230100787Sfenner if (cc < 0) 1231100787Sfenner Fprintf(stderr, "%s: sendto: %s\n", 1232100787Sfenner prog, strerror(errno)); 1233100787Sfenner Printf("%s: wrote %s %d chars, ret=%d\n", 1234100787Sfenner prog, hostname, packlen, cc); 1235100787Sfenner (void)fflush(stdout); 1236100787Sfenner } 1237100787Sfenner} 1238100787Sfenner 123958804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 124058804Sshinint 124158804Sshinsetpolicy(so, policy) 124258804Sshin int so; 124358804Sshin char *policy; 124458804Sshin{ 124558804Sshin char *buf; 124658804Sshin 124758804Sshin buf = ipsec_set_policy(policy, strlen(policy)); 124858804Sshin if (buf == NULL) { 124966809Skris warnx("%s", ipsec_strerror()); 125058804Sshin return -1; 125158804Sshin } 125258804Sshin (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY, 125358804Sshin buf, ipsec_get_policylen(buf)); 125458804Sshin 125558804Sshin free(buf); 125658804Sshin 125758804Sshin return 0; 125858804Sshin} 125958804Sshin#endif 126058804Sshin 126118579Sfennerdouble 126218579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p) 126318579Sfenner{ 126418579Sfenner register double dt; 126518579Sfenner 126618579Sfenner dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 126718579Sfenner (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 126818579Sfenner return (dt); 126918579Sfenner} 127018579Sfenner 127118579Sfenner/* 127218579Sfenner * Convert an ICMP "type" field to a printable string. 127318579Sfenner */ 127418579Sfennerchar * 127518579Sfennerpr_type(register u_char t) 127618579Sfenner{ 127718579Sfenner static char *ttab[] = { 127818579Sfenner "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 127918579Sfenner "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 128018579Sfenner "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 128118579Sfenner "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 128218579Sfenner "Info Reply" 128318579Sfenner }; 128418579Sfenner 128518579Sfenner if (t > 16) 128618579Sfenner return("OUT-OF-RANGE"); 128718579Sfenner 128818579Sfenner return(ttab[t]); 128918579Sfenner} 129018579Sfenner 129118579Sfennerint 129218579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from, 129318579Sfenner register int seq) 129418579Sfenner{ 129518579Sfenner register struct icmp *icp; 129618579Sfenner register u_char type, code; 129718579Sfenner register int hlen; 129818579Sfenner#ifndef ARCHAIC 129918579Sfenner register struct ip *ip; 130018579Sfenner 130118579Sfenner ip = (struct ip *) buf; 130218579Sfenner hlen = ip->ip_hl << 2; 130318579Sfenner if (cc < hlen + ICMP_MINLEN) { 130418579Sfenner if (verbose) 130518579Sfenner Printf("packet too short (%d bytes) from %s\n", cc, 130618579Sfenner inet_ntoa(from->sin_addr)); 130718579Sfenner return (0); 130818579Sfenner } 130918579Sfenner cc -= hlen; 131018579Sfenner icp = (struct icmp *)(buf + hlen); 131118579Sfenner#else 131218579Sfenner icp = (struct icmp *)buf; 131318579Sfenner#endif 131418579Sfenner type = icp->icmp_type; 131518579Sfenner code = icp->icmp_code; 1316100787Sfenner /* Path MTU Discovery (RFC1191) */ 1317100787Sfenner if (code != ICMP_UNREACH_NEEDFRAG) 1318100787Sfenner pmtu = 0; 1319100787Sfenner else { 1320100787Sfenner#ifdef HAVE_ICMP_NEXTMTU 1321100787Sfenner pmtu = ntohs(icp->icmp_nextmtu); 1322100787Sfenner#else 1323100787Sfenner pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu); 1324100787Sfenner#endif 1325100787Sfenner } 1326100535Sfenner if (type == ICMP_ECHOREPLY 1327100535Sfenner && proto->num == IPPROTO_ICMP 1328124859Scperciva && (*proto->check)((u_char *)icp, (u_char)seq)) 1329100535Sfenner return -2; 133018579Sfenner if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 133118579Sfenner type == ICMP_UNREACH) { 133246542Sarchie u_char *inner; 133318579Sfenner 133418579Sfenner hip = &icp->icmp_ip; 1335163387Sdwmalone hiplen = ((u_char *)icp + cc) - (u_char *)hip; 133618579Sfenner hlen = hip->ip_hl << 2; 133746542Sarchie inner = (u_char *)((u_char *)hip + hlen); 133846542Sarchie if (hlen + 12 <= cc 133946542Sarchie && hip->ip_p == proto->num 1340124859Scperciva && (*proto->check)(inner, (u_char)seq)) 134118579Sfenner return (type == ICMP_TIMXCEED ? -1 : code + 1); 134218579Sfenner } 134318579Sfenner#ifndef ARCHAIC 134418579Sfenner if (verbose) { 134518579Sfenner register int i; 134618579Sfenner u_int32_t *lp = (u_int32_t *)&icp->icmp_ip; 134718579Sfenner 134818579Sfenner Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr)); 134918579Sfenner Printf("%s: icmp type %d (%s) code %d\n", 135018579Sfenner inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); 135118579Sfenner for (i = 4; i < cc ; i += sizeof(*lp)) 135218579Sfenner Printf("%2d: x%8.8x\n", i, *lp++); 135318579Sfenner } 135418579Sfenner#endif 135518579Sfenner return(0); 135618579Sfenner} 135718579Sfenner 135846542Sarchievoid 1359100535Sfennericmp_prep(struct outdata *outdata) 1360100535Sfenner{ 1361100787Sfenner struct icmp *const icmpheader = (struct icmp *) outp; 1362100535Sfenner 1363100535Sfenner icmpheader->icmp_type = ICMP_ECHO; 1364100535Sfenner icmpheader->icmp_id = htons(ident); 1365100535Sfenner icmpheader->icmp_seq = htons(outdata->seq); 1366100535Sfenner icmpheader->icmp_cksum = 0; 1367100789Sfenner icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen); 1368100535Sfenner if (icmpheader->icmp_cksum == 0) 1369100535Sfenner icmpheader->icmp_cksum = 0xffff; 1370100535Sfenner} 1371100535Sfenner 1372100535Sfennerint 1373100535Sfennericmp_check(const u_char *data, int seq) 1374100535Sfenner{ 1375100535Sfenner struct icmp *const icmpheader = (struct icmp *) data; 1376100535Sfenner 1377100535Sfenner return (icmpheader->icmp_id == htons(ident) 1378100535Sfenner && icmpheader->icmp_seq == htons(seq)); 1379100535Sfenner} 1380100535Sfenner 1381100535Sfennervoid 138246542Sarchieudp_prep(struct outdata *outdata) 138346542Sarchie{ 1384100787Sfenner struct udphdr *const outudp = (struct udphdr *) outp; 138518579Sfenner 1386158424Scjc outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0)); 1387158424Scjc outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1388100787Sfenner outudp->uh_ulen = htons((u_short)protlen); 1389100789Sfenner outudp->uh_sum = 0; 1390100787Sfenner if (doipcksum) { 1391100789Sfenner u_short sum = p_cksum(outip, (u_short*)outudp, protlen); 1392100789Sfenner outudp->uh_sum = (sum) ? sum : 0xffff; 1393100787Sfenner } 1394100789Sfenner 1395100789Sfenner return; 139646542Sarchie} 139746542Sarchie 139846542Sarchieint 139946542Sarchieudp_check(const u_char *data, int seq) 140046542Sarchie{ 140146542Sarchie struct udphdr *const udp = (struct udphdr *) data; 140246542Sarchie 1403158424Scjc return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) && 1404158424Scjc ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq)); 140546542Sarchie} 140646542Sarchie 140718579Sfennervoid 140846542Sarchietcp_prep(struct outdata *outdata) 140946542Sarchie{ 1410100787Sfenner struct tcphdr *const tcp = (struct tcphdr *) outp; 141146542Sarchie 141246542Sarchie tcp->th_sport = htons(ident); 1413158424Scjc tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1414158424Scjc tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport + 1415158424Scjc (fixedPort ? outdata->seq : 0)); 141646542Sarchie tcp->th_ack = 0; 141746542Sarchie tcp->th_off = 5; 141846542Sarchie tcp->th_flags = TH_SYN; 1419100789Sfenner tcp->th_sum = 0; 1420100789Sfenner 1421100789Sfenner if (doipcksum) { 1422100789Sfenner u_short sum = p_cksum(outip, (u_short*)tcp, protlen); 1423100789Sfenner tcp->th_sum = (sum) ? sum : 0xffff; 1424100789Sfenner } 142546542Sarchie} 142646542Sarchie 142746542Sarchieint 142846542Sarchietcp_check(const u_char *data, int seq) 142946542Sarchie{ 143046542Sarchie struct tcphdr *const tcp = (struct tcphdr *) data; 143146542Sarchie 143246542Sarchie return (ntohs(tcp->th_sport) == ident 1433158424Scjc && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq)) 1434158424Scjc && tcp->th_seq == (ident << 16) | (port + seq); 143546542Sarchie} 143646542Sarchie 143746542Sarchievoid 143846542Sarchiegre_prep(struct outdata *outdata) 143946542Sarchie{ 1440100787Sfenner struct grehdr *const gre = (struct grehdr *) outp; 144146542Sarchie 144246542Sarchie gre->flags = htons(0x2001); 144346542Sarchie gre->proto = htons(port); 144446542Sarchie gre->length = 0; 144546542Sarchie gre->callId = htons(ident + outdata->seq); 144646542Sarchie} 144746542Sarchie 144846542Sarchieint 144946542Sarchiegre_check(const u_char *data, int seq) 145046542Sarchie{ 145146542Sarchie struct grehdr *const gre = (struct grehdr *) data; 145246542Sarchie 145346542Sarchie return(ntohs(gre->proto) == port 145446542Sarchie && ntohs(gre->callId) == ident + seq); 145546542Sarchie} 145646542Sarchie 145746542Sarchievoid 145846542Sarchiegen_prep(struct outdata *outdata) 145946542Sarchie{ 1460100787Sfenner u_int16_t *const ptr = (u_int16_t *) outp; 146146542Sarchie 146246542Sarchie ptr[0] = htons(ident); 146346542Sarchie ptr[1] = htons(port + outdata->seq); 146446542Sarchie} 146546542Sarchie 146646542Sarchieint 146746542Sarchiegen_check(const u_char *data, int seq) 146846542Sarchie{ 146946542Sarchie u_int16_t *const ptr = (u_int16_t *) data; 147046542Sarchie 147146542Sarchie return(ntohs(ptr[0]) == ident 147246542Sarchie && ntohs(ptr[1]) == port + seq); 147346542Sarchie} 147446542Sarchie 147546542Sarchievoid 147618579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from) 147718579Sfenner{ 147818579Sfenner register struct ip *ip; 147918579Sfenner register int hlen; 148018579Sfenner 148118579Sfenner ip = (struct ip *) buf; 148218579Sfenner hlen = ip->ip_hl << 2; 148318579Sfenner cc -= hlen; 148418579Sfenner 1485176428Srpaulo if (as_path) 1486176428Srpaulo Printf(" [AS%d]", as_lookup(asn, &from->sin_addr)); 1487176428Srpaulo 148818579Sfenner if (nflag) 148918579Sfenner Printf(" %s", inet_ntoa(from->sin_addr)); 149018579Sfenner else 149118579Sfenner Printf(" %s (%s)", inetname(from->sin_addr), 149218579Sfenner inet_ntoa(from->sin_addr)); 149318579Sfenner 149418579Sfenner if (verbose) 149518579Sfenner Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 149618579Sfenner} 149718579Sfenner 149818579Sfenner/* 1499100789Sfenner * Checksum routine for UDP and TCP headers. 1500100789Sfenner */ 1501100789Sfenneru_short 1502100789Sfennerp_cksum(struct ip *ip, u_short *data, int len) 1503100789Sfenner{ 1504100789Sfenner static struct ipovly ipo; 1505100789Sfenner u_short sumh, sumd; 1506100789Sfenner u_long sumt; 1507100789Sfenner 1508100789Sfenner ipo.ih_pr = ip->ip_p; 1509100789Sfenner ipo.ih_len = htons(len); 1510100789Sfenner ipo.ih_src = ip->ip_src; 1511100789Sfenner ipo.ih_dst = ip->ip_dst; 1512100789Sfenner 1513100789Sfenner sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */ 1514100789Sfenner sumd = in_cksum((u_short*)data, len); /* payload data cksum */ 1515100789Sfenner sumt = (sumh << 16) | (sumd); 1516100789Sfenner 1517100789Sfenner return ~in_cksum((u_short*)&sumt, sizeof(sumt)); 1518100789Sfenner} 1519100789Sfenner 1520100789Sfenner/* 152118579Sfenner * Checksum routine for Internet Protocol family headers (C Version) 152218579Sfenner */ 1523100535Sfenneru_short 152418579Sfennerin_cksum(register u_short *addr, register int len) 152518579Sfenner{ 152618579Sfenner register int nleft = len; 152718579Sfenner register u_short *w = addr; 152818579Sfenner register u_short answer; 152918579Sfenner register int sum = 0; 153018579Sfenner 153118579Sfenner /* 153218579Sfenner * Our algorithm is simple, using a 32 bit accumulator (sum), 153318579Sfenner * we add sequential 16 bit words to it, and at the end, fold 153418579Sfenner * back all the carry bits from the top 16 bits into the lower 153518579Sfenner * 16 bits. 153618579Sfenner */ 153718579Sfenner while (nleft > 1) { 153818579Sfenner sum += *w++; 153918579Sfenner nleft -= 2; 154018579Sfenner } 154118579Sfenner 154218579Sfenner /* mop up an odd byte, if necessary */ 154318579Sfenner if (nleft == 1) 154418579Sfenner sum += *(u_char *)w; 154518579Sfenner 154618579Sfenner /* 154718579Sfenner * add back carry outs from top 16 bits to low 16 bits 154818579Sfenner */ 154918579Sfenner sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 155018579Sfenner sum += (sum >> 16); /* add carry */ 155118579Sfenner answer = ~sum; /* truncate to 16 bits */ 155218579Sfenner return (answer); 155318579Sfenner} 155418579Sfenner 155518579Sfenner/* 155618579Sfenner * Subtract 2 timeval structs: out = out - in. 155744086Sdes * Out is assumed to be within about LONG_MAX seconds of in. 155818579Sfenner */ 155918579Sfennervoid 156018579Sfennertvsub(register struct timeval *out, register struct timeval *in) 156118579Sfenner{ 156218579Sfenner 156318579Sfenner if ((out->tv_usec -= in->tv_usec) < 0) { 156418579Sfenner --out->tv_sec; 156518579Sfenner out->tv_usec += 1000000; 156618579Sfenner } 156718579Sfenner out->tv_sec -= in->tv_sec; 156818579Sfenner} 156918579Sfenner 157018579Sfenner/* 157118579Sfenner * Construct an Internet address representation. 157218579Sfenner * If the nflag has been supplied, give 157318579Sfenner * numeric value, otherwise try for symbolic name. 157418579Sfenner */ 157518579Sfennerchar * 157618579Sfennerinetname(struct in_addr in) 157718579Sfenner{ 157818579Sfenner register char *cp; 157918579Sfenner register struct hostent *hp; 158018579Sfenner static int first = 1; 158118579Sfenner static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1]; 158218579Sfenner 158318579Sfenner if (first && !nflag) { 158418579Sfenner first = 0; 1585100787Sfenner if (gethostname(domain, sizeof(domain) - 1) < 0) 158618579Sfenner domain[0] = '\0'; 1587100787Sfenner else { 1588100787Sfenner cp = strchr(domain, '.'); 1589100787Sfenner if (cp == NULL) { 1590100787Sfenner hp = gethostbyname(domain); 1591100787Sfenner if (hp != NULL) 1592100787Sfenner cp = strchr(hp->h_name, '.'); 1593100787Sfenner } 1594100787Sfenner if (cp == NULL) 1595100787Sfenner domain[0] = '\0'; 1596100787Sfenner else { 1597100787Sfenner ++cp; 1598100787Sfenner (void)strncpy(domain, cp, sizeof(domain) - 1); 1599100787Sfenner domain[sizeof(domain) - 1] = '\0'; 1600100787Sfenner } 1601100787Sfenner } 160218579Sfenner } 160318579Sfenner if (!nflag && in.s_addr != INADDR_ANY) { 160418579Sfenner hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); 160518579Sfenner if (hp != NULL) { 160618579Sfenner if ((cp = strchr(hp->h_name, '.')) != NULL && 160718579Sfenner strcmp(cp + 1, domain) == 0) 160818579Sfenner *cp = '\0'; 160918579Sfenner (void)strncpy(line, hp->h_name, sizeof(line) - 1); 161018579Sfenner line[sizeof(line) - 1] = '\0'; 161118579Sfenner return (line); 161218579Sfenner } 161318579Sfenner } 161418579Sfenner return (inet_ntoa(in)); 161518579Sfenner} 161618579Sfenner 1617100787Sfennerstruct hostinfo * 1618100787Sfennergethostinfo(register char *hostname) 161918579Sfenner{ 1620100787Sfenner register int n; 162118579Sfenner register struct hostent *hp; 1622100787Sfenner register struct hostinfo *hi; 1623100787Sfenner register char **p; 1624100787Sfenner register u_int32_t addr, *ap; 162518579Sfenner 1626100787Sfenner if (strlen(hostname) > 64) { 1627100787Sfenner Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", 1628100787Sfenner prog, hostname); 1629100787Sfenner exit(1); 1630100787Sfenner } 1631100787Sfenner hi = calloc(1, sizeof(*hi)); 1632100787Sfenner if (hi == NULL) { 1633100787Sfenner Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1634100787Sfenner exit(1); 1635100787Sfenner } 1636100787Sfenner addr = inet_addr(hostname); 1637100787Sfenner if ((int32_t)addr != -1) { 1638100787Sfenner hi->name = strdup(hostname); 1639100787Sfenner hi->n = 1; 1640100787Sfenner hi->addrs = calloc(1, sizeof(hi->addrs[0])); 1641100787Sfenner if (hi->addrs == NULL) { 1642100787Sfenner Fprintf(stderr, "%s: calloc %s\n", 1643100787Sfenner prog, strerror(errno)); 1644100787Sfenner exit(1); 1645100787Sfenner } 1646100787Sfenner hi->addrs[0] = addr; 1647100787Sfenner return (hi); 1648100787Sfenner } 164918579Sfenner 165018579Sfenner hp = gethostbyname(hostname); 165118579Sfenner if (hp == NULL) { 165218579Sfenner Fprintf(stderr, "%s: unknown host %s\n", prog, hostname); 165318579Sfenner exit(1); 165418579Sfenner } 165518579Sfenner if (hp->h_addrtype != AF_INET || hp->h_length != 4) { 165618579Sfenner Fprintf(stderr, "%s: bad host %s\n", prog, hostname); 165718579Sfenner exit(1); 165818579Sfenner } 1659100787Sfenner hi->name = strdup(hp->h_name); 1660100787Sfenner for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) 1661100787Sfenner continue; 1662100787Sfenner hi->n = n; 1663100787Sfenner hi->addrs = calloc(n, sizeof(hi->addrs[0])); 1664100787Sfenner if (hi->addrs == NULL) { 1665100787Sfenner Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1666100787Sfenner exit(1); 1667100787Sfenner } 1668100787Sfenner for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) 1669100787Sfenner memcpy(ap, *p, sizeof(*ap)); 1670100787Sfenner return (hi); 167118579Sfenner} 167218579Sfenner 1673100787Sfennervoid 1674100787Sfennerfreehostinfo(register struct hostinfo *hi) 167518579Sfenner{ 1676100787Sfenner if (hi->name != NULL) { 1677100787Sfenner free(hi->name); 1678100787Sfenner hi->name = NULL; 1679100787Sfenner } 1680100787Sfenner free((char *)hi->addrs); 1681100787Sfenner free((char *)hi); 1682100787Sfenner} 168318579Sfenner 1684100787Sfennervoid 1685100787Sfennergetaddr(register u_int32_t *ap, register char *hostname) 1686100787Sfenner{ 1687100787Sfenner register struct hostinfo *hi; 1688100787Sfenner 1689100787Sfenner hi = gethostinfo(hostname); 1690100787Sfenner *ap = hi->addrs[0]; 1691100787Sfenner freehostinfo(hi); 1692100787Sfenner} 1693100787Sfenner 1694100787Sfennervoid 1695100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr) 1696100787Sfenner{ 1697100787Sfenner 169818579Sfenner memset(sin, 0, sizeof(*sin)); 1699100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN 1700100787Sfenner sin->sin_len = sizeof(*sin); 1701100787Sfenner#endif 170218579Sfenner sin->sin_family = AF_INET; 1703100787Sfenner sin->sin_addr.s_addr = addr; 170418579Sfenner} 170518579Sfenner 1706100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */ 1707100787Sfennerint 1708100787Sfennerstr2val(register const char *str, register const char *what, 1709100787Sfenner register int mi, register int ma) 171018579Sfenner{ 1711100787Sfenner register const char *cp; 1712100787Sfenner register int val; 1713100787Sfenner char *ep; 171418579Sfenner 1715100787Sfenner if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 1716100787Sfenner cp = str + 2; 1717100787Sfenner val = (int)strtol(cp, &ep, 16); 1718100787Sfenner } else 1719100787Sfenner val = (int)strtol(str, &ep, 10); 1720100787Sfenner if (*ep != '\0') { 1721100787Sfenner Fprintf(stderr, "%s: \"%s\" bad value for %s \n", 1722100787Sfenner prog, str, what); 172318579Sfenner exit(1); 172418579Sfenner } 1725100787Sfenner if (val < mi && mi >= 0) { 1726100787Sfenner if (mi == 0) 1727100787Sfenner Fprintf(stderr, "%s: %s must be >= %d\n", 1728100787Sfenner prog, what, mi); 1729100787Sfenner else 1730100787Sfenner Fprintf(stderr, "%s: %s must be > %d\n", 1731100787Sfenner prog, what, mi - 1); 1732100787Sfenner exit(1); 1733100787Sfenner } 1734100787Sfenner if (val > ma && ma >= 0) { 1735100787Sfenner Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); 1736100787Sfenner exit(1); 1737100787Sfenner } 1738100787Sfenner return (val); 173918579Sfenner} 174018579Sfenner 1741100787Sfennerstruct outproto * 1742100787Sfennersetproto(char *pname) 1743100787Sfenner{ 1744100787Sfenner struct outproto *proto; 1745100787Sfenner int i; 1746100787Sfenner 1747100787Sfenner for (i = 0; protos[i].name != NULL; i++) { 1748100787Sfenner if (strcasecmp(protos[i].name, pname) == 0) { 1749100787Sfenner break; 1750100787Sfenner } 1751100787Sfenner } 1752100787Sfenner proto = &protos[i]; 1753100787Sfenner if (proto->name == NULL) { /* generic handler */ 1754100787Sfenner struct protoent *pe; 1755100787Sfenner u_long pnum; 1756100787Sfenner 1757100787Sfenner /* Determine the IP protocol number */ 1758100787Sfenner if ((pe = getprotobyname(pname)) != NULL) 1759100787Sfenner pnum = pe->p_proto; 1760100787Sfenner else 1761100787Sfenner pnum = str2val(optarg, "proto number", 1, 255); 1762100787Sfenner proto->num = pnum; 1763100787Sfenner } 1764100787Sfenner return proto; 1765100787Sfenner} 1766100787Sfenner 176767682Sobrienvoid 1768163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) { 1769163387Sdwmalone int l; 1770163387Sdwmalone int i; 1771163387Sdwmalone 1772163387Sdwmalone for (i = 0; i < la; i++) 1773163387Sdwmalone Printf("%02x", (unsigned int)a[i]); 1774163387Sdwmalone Printf("\n"); 1775163387Sdwmalone l = (la <= lb) ? la : lb; 1776163387Sdwmalone for (i = 0; i < l; i++) 1777163387Sdwmalone if (a[i] == b[i]) 1778163387Sdwmalone Printf("__"); 1779163387Sdwmalone else 1780163387Sdwmalone Printf("%02x", (unsigned int)b[i]); 1781163387Sdwmalone for (; i < lb; i++) 1782163387Sdwmalone Printf("%02x", (unsigned int)b[i]); 1783163387Sdwmalone Printf("\n"); 1784163387Sdwmalone} 1785163387Sdwmalone 1786163387Sdwmalone 1787163387Sdwmalonevoid 178818579Sfennerusage(void) 178918579Sfenner{ 179018579Sfenner extern char version[]; 179118579Sfenner 179218579Sfenner Fprintf(stderr, "Version %s\n", version); 1793100787Sfenner Fprintf(stderr, 1794176428Srpaulo "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n" 1795100787Sfenner "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n" 1796176428Srpaulo "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog); 179718579Sfenner exit(1); 179818579Sfenner} 1799