traceroute.c revision 216184
118579Sfenner/* 2100787Sfenner * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000 318579Sfenner * The Regents of the University of California. All rights reserved. 418579Sfenner * 518579Sfenner * Redistribution and use in source and binary forms, with or without 618579Sfenner * modification, are permitted provided that: (1) source code distributions 718579Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 818579Sfenner * distributions including binary code include the above copyright notice and 918579Sfenner * this paragraph in its entirety in the documentation or other materials 1018579Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1118579Sfenner * features or use of this software display the following acknowledgement: 1218579Sfenner * ``This product includes software developed by the University of California, 1318579Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1418579Sfenner * the University nor the names of its contributors may be used to endorse 1518579Sfenner * or promote products derived from this software without specific prior 1618579Sfenner * written permission. 1718579Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1818579Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1918579Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2018579Sfenner */ 2118579Sfenner 2218579Sfenner#ifndef lint 2318579Sfennerstatic const char copyright[] = 24100787Sfenner "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\ 2518579SfennerThe Regents of the University of California. All rights reserved.\n"; 2658835Sshin#if 0 2718579Sfennerstatic const char rcsid[] = 28100787Sfenner "@(#)$Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp $ (LBL)"; 2918579Sfenner#endif 3058835Sshinstatic const char rcsid[] = 3158835Sshin "$FreeBSD: head/contrib/traceroute/traceroute.c 216184 2010-12-04 14:19:27Z uqs $"; 3258835Sshin#endif 3318579Sfenner 3418579Sfenner/* 3518579Sfenner * traceroute host - trace the route ip packets follow going to "host". 3618579Sfenner * 3718579Sfenner * Attempt to trace the route an ip packet would follow to some 3818579Sfenner * internet host. We find out intermediate hops by launching probe 3918579Sfenner * packets with a small ttl (time to live) then listening for an 4018579Sfenner * icmp "time exceeded" reply from a gateway. We start our probes 4118579Sfenner * with a ttl of one and increase by one until we get an icmp "port 4218579Sfenner * unreachable" (which means we got to "host") or hit a max (which 4377816Sru * defaults to net.inet.ip.ttl hops & can be changed with the -m flag). 4477816Sru * Three probes (change with -q flag) are sent at each ttl setting and 4577816Sru * a line is printed showing the ttl, address of the gateway and 4618579Sfenner * round trip time of each probe. If the probe answers come from 4718579Sfenner * different gateways, the address of each responding system will 4818579Sfenner * be printed. If there is no response within a 5 sec. timeout 4918579Sfenner * interval (changed with the -w flag), a "*" is printed for that 5018579Sfenner * probe. 5118579Sfenner * 5218579Sfenner * Probe packets are UDP format. We don't want the destination 5318579Sfenner * host to process them so the destination port is set to an 5418579Sfenner * unlikely value (if some clod on the destination is using that 5518579Sfenner * value, it can be changed with the -p flag). 5618579Sfenner * 5718579Sfenner * A sample use might be: 5818579Sfenner * 5918579Sfenner * [yak 71]% traceroute nis.nsf.net. 6077816Sru * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet 6118579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 6218579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 6318579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 6418579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 6518579Sfenner * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 6618579Sfenner * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 6718579Sfenner * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 6818579Sfenner * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 6918579Sfenner * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 7018579Sfenner * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 7118579Sfenner * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 7218579Sfenner * 7318579Sfenner * Note that lines 2 & 3 are the same. This is due to a buggy 7418579Sfenner * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 7518579Sfenner * packets with a zero ttl. 7618579Sfenner * 7718579Sfenner * A more interesting example is: 7818579Sfenner * 7918579Sfenner * [yak 72]% traceroute allspice.lcs.mit.edu. 8077816Sru * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max 8118579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 8218579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 8318579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 8418579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 8518579Sfenner * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 8618579Sfenner * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 8718579Sfenner * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 8818579Sfenner * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 8918579Sfenner * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 9018579Sfenner * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 9118579Sfenner * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 9218579Sfenner * 12 * * * 9318579Sfenner * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 9418579Sfenner * 14 * * * 9518579Sfenner * 15 * * * 9618579Sfenner * 16 * * * 9718579Sfenner * 17 * * * 9818579Sfenner * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 9918579Sfenner * 10018579Sfenner * (I start to see why I'm having so much trouble with mail to 10118579Sfenner * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 10218579Sfenner * either don't send ICMP "time exceeded" messages or send them 10318579Sfenner * with a ttl too small to reach us. 14 - 17 are running the 10418579Sfenner * MIT C Gateway code that doesn't send "time exceeded"s. God 10518579Sfenner * only knows what's going on with 12. 10618579Sfenner * 10718579Sfenner * The silent gateway 12 in the above may be the result of a bug in 10818579Sfenner * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 10918579Sfenner * sends an unreachable message using whatever ttl remains in the 11018579Sfenner * original datagram. Since, for gateways, the remaining ttl is 11118579Sfenner * zero, the icmp "time exceeded" is guaranteed to not make it back 11218579Sfenner * to us. The behavior of this bug is slightly more interesting 11318579Sfenner * when it appears on the destination system: 11418579Sfenner * 11518579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 11618579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 11718579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 11818579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 11918579Sfenner * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 12018579Sfenner * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 12118579Sfenner * 7 * * * 12218579Sfenner * 8 * * * 12318579Sfenner * 9 * * * 12418579Sfenner * 10 * * * 12518579Sfenner * 11 * * * 12618579Sfenner * 12 * * * 12718579Sfenner * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 12818579Sfenner * 12918579Sfenner * Notice that there are 12 "gateways" (13 is the final 13018579Sfenner * destination) and exactly the last half of them are "missing". 13118579Sfenner * What's really happening is that rip (a Sun-3 running Sun OS3.5) 13218579Sfenner * is using the ttl from our arriving datagram as the ttl in its 13318579Sfenner * icmp reply. So, the reply will time out on the return path 13418579Sfenner * (with no notice sent to anyone since icmp's aren't sent for 13518579Sfenner * icmp's) until we probe with a ttl that's at least twice the path 13618579Sfenner * length. I.e., rip is really only 7 hops away. A reply that 13718579Sfenner * returns with a ttl of 1 is a clue this problem exists. 13818579Sfenner * Traceroute prints a "!" after the time if the ttl is <= 1. 13918579Sfenner * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 14018579Sfenner * non-standard (HPUX) software, expect to see this problem 14118579Sfenner * frequently and/or take care picking the target host of your 14218579Sfenner * probes. 14318579Sfenner * 14418579Sfenner * Other possible annotations after the time are !H, !N, !P (got a host, 14518579Sfenner * network or protocol unreachable, respectively), !S or !F (source 14618579Sfenner * route failed or fragmentation needed -- neither of these should 14718579Sfenner * ever occur and the associated gateway is busted if you see one). If 14818579Sfenner * almost all the probes result in some kind of unreachable, traceroute 14918579Sfenner * will give up and exit. 15018579Sfenner * 15118579Sfenner * Notes 15218579Sfenner * ----- 15318579Sfenner * This program must be run by root or be setuid. (I suggest that 15418579Sfenner * you *don't* make it setuid -- casual use could result in a lot 15518579Sfenner * of unnecessary traffic on our poor, congested nets.) 15618579Sfenner * 15718579Sfenner * This program requires a kernel mod that does not appear in any 15818579Sfenner * system available from Berkeley: A raw ip socket using proto 15918579Sfenner * IPPROTO_RAW must interpret the data sent as an ip datagram (as 16018579Sfenner * opposed to data to be wrapped in a ip datagram). See the README 16118579Sfenner * file that came with the source to this program for a description 16218579Sfenner * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 16318579Sfenner * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 16418579Sfenner * MODIFIED TO RUN THIS PROGRAM. 16518579Sfenner * 16618579Sfenner * The udp port usage may appear bizarre (well, ok, it is bizarre). 16718579Sfenner * The problem is that an icmp message only contains 8 bytes of 16818579Sfenner * data from the original datagram. 8 bytes is the size of a udp 16918579Sfenner * header so, if we want to associate replies with the original 17018579Sfenner * datagram, the necessary information must be encoded into the 17118579Sfenner * udp header (the ip id could be used but there's no way to 17218579Sfenner * interlock with the kernel's assignment of ip id's and, anyway, 17318579Sfenner * it would have taken a lot more kernel hacking to allow this 17418579Sfenner * code to set the ip id). So, to allow two or more users to 17518579Sfenner * use traceroute simultaneously, we use this task's pid as the 17618579Sfenner * source port (the high bit is set to move the port number out 17718579Sfenner * of the "likely" range). To keep track of which probe is being 17818579Sfenner * replied to (so times and/or hop counts don't get confused by a 17918579Sfenner * reply that was delayed in transit), we increment the destination 18018579Sfenner * port number before each probe. 18118579Sfenner * 18218579Sfenner * Don't use this as a coding example. I was trying to find a 18318579Sfenner * routing problem and this code sort-of popped out after 48 hours 18418579Sfenner * without sleep. I was amazed it ever compiled, much less ran. 18518579Sfenner * 18618579Sfenner * I stole the idea for this program from Steve Deering. Since 18718579Sfenner * the first release, I've learned that had I attended the right 18818579Sfenner * IETF working group meetings, I also could have stolen it from Guy 18918579Sfenner * Almes or Matt Mathis. I don't know (or care) who came up with 19018579Sfenner * the idea first. I envy the originators' perspicacity and I'm 19118579Sfenner * glad they didn't keep the idea a secret. 19218579Sfenner * 19318579Sfenner * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 19418579Sfenner * enhancements to the original distribution. 19518579Sfenner * 19618579Sfenner * I've hacked up a round-trip-route version of this that works by 19718579Sfenner * sending a loose-source-routed udp datagram through the destination 19818579Sfenner * back to yourself. Unfortunately, SO many gateways botch source 19918579Sfenner * routing, the thing is almost worthless. Maybe one day... 20018579Sfenner * 20118579Sfenner * -- Van Jacobson (van@ee.lbl.gov) 20218579Sfenner * Tue Dec 20 03:50:13 PST 1988 20318579Sfenner */ 20418579Sfenner 20518579Sfenner#include <sys/param.h> 20618579Sfenner#include <sys/file.h> 20718579Sfenner#include <sys/ioctl.h> 20818579Sfenner#ifdef HAVE_SYS_SELECT_H 20918579Sfenner#include <sys/select.h> 21018579Sfenner#endif 21118579Sfenner#include <sys/socket.h> 21277816Sru#ifdef HAVE_SYS_SYSCTL_H 21377816Sru#include <sys/sysctl.h> 21477816Sru#endif 21518579Sfenner#include <sys/time.h> 21618579Sfenner 21718579Sfenner#include <netinet/in_systm.h> 21818579Sfenner#include <netinet/in.h> 21918579Sfenner#include <netinet/ip.h> 22018579Sfenner#include <netinet/ip_var.h> 22118579Sfenner#include <netinet/ip_icmp.h> 22218579Sfenner#include <netinet/udp.h> 22346542Sarchie#include <netinet/tcp.h> 224100789Sfenner#include <netinet/tcpip.h> 22518579Sfenner 22618579Sfenner#include <arpa/inet.h> 22718579Sfenner 22858804Sshin#ifdef IPSEC 22958804Sshin#include <net/route.h> 230171135Sgnn#include <netipsec/ipsec.h> /* XXX */ 23158804Sshin#endif /* IPSEC */ 23258804Sshin 23318579Sfenner#include <ctype.h> 234100787Sfenner#include <err.h> 23518579Sfenner#include <errno.h> 236100787Sfenner#include <fcntl.h> 23718579Sfenner#ifdef HAVE_MALLOC_H 23818579Sfenner#include <malloc.h> 23918579Sfenner#endif 24018579Sfenner#include <memory.h> 24118579Sfenner#include <netdb.h> 24218579Sfenner#include <stdio.h> 24318579Sfenner#include <stdlib.h> 24418579Sfenner#include <string.h> 24518579Sfenner#include <unistd.h> 24618579Sfenner 247100787Sfenner/* rfc1716 */ 248100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB 249100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ 250100787Sfenner#endif 251100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE 252100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ 253100787Sfenner#endif 254100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF 255100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ 256100787Sfenner#endif 257100787Sfenner 258100787Sfenner#include "findsaddr.h" 259100787Sfenner#include "ifaddrlist.h" 260176428Srpaulo#include "as.h" 261100787Sfenner#include "traceroute.h" 262100787Sfenner 26318579Sfenner/* Maximum number of gateways (include room for one noop) */ 26418579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) 26518579Sfenner 26618579Sfenner#ifndef MAXHOSTNAMELEN 26718579Sfenner#define MAXHOSTNAMELEN 64 26818579Sfenner#endif 26918579Sfenner 27018579Sfenner#define Fprintf (void)fprintf 27118579Sfenner#define Printf (void)printf 27218579Sfenner 27346542Sarchie/* What a GRE packet header looks like */ 27446542Sarchiestruct grehdr { 27546542Sarchie u_int16_t flags; 27646542Sarchie u_int16_t proto; 27746542Sarchie u_int16_t length; /* PPTP version of these fields */ 27846542Sarchie u_int16_t callId; 27946542Sarchie}; 28046542Sarchie#ifndef IPPROTO_GRE 28146542Sarchie#define IPPROTO_GRE 47 28246542Sarchie#endif 28346542Sarchie 28446542Sarchie/* For GRE, we prepare what looks like a PPTP packet */ 28546542Sarchie#define GRE_PPTP_PROTO 0x880b 28646542Sarchie 287100787Sfenner/* Host name and address list */ 288100787Sfennerstruct hostinfo { 289100787Sfenner char *name; 290100787Sfenner int n; 291100787Sfenner u_int32_t *addrs; 292100787Sfenner}; 293100787Sfenner 29418579Sfenner/* Data section of the probe packet */ 29518579Sfennerstruct outdata { 29618579Sfenner u_char seq; /* sequence number of this packet */ 29718579Sfenner u_char ttl; /* ttl packet left with */ 29818579Sfenner struct timeval tv; /* time packet left */ 29918579Sfenner}; 30018579Sfenner 301100787Sfenner#ifndef HAVE_ICMP_NEXTMTU 302100787Sfenner/* Path MTU Discovery (RFC1191) */ 303100787Sfennerstruct my_pmtu { 304100787Sfenner u_short ipm_void; 305100787Sfenner u_short ipm_nextmtu; 30646542Sarchie}; 307100787Sfenner#endif 30846542Sarchie 30918579Sfenneru_char packet[512]; /* last inbound (icmp) packet */ 31018579Sfenner 31146542Sarchiestruct ip *outip; /* last output ip packet */ 312100787Sfenneru_char *outp; /* last output inner protocol packet */ 31318579Sfenner 314163387Sdwmalonestruct ip *hip = NULL; /* Quoted IP header */ 315163387Sdwmaloneint hiplen = 0; 316163387Sdwmalone 31718579Sfenner/* loose source route gateway list (including room for final destination) */ 31818579Sfenneru_int32_t gwlist[NGATEWAYS + 1]; 31918579Sfenner 32018579Sfennerint s; /* receive (icmp) socket file descriptor */ 32118579Sfennerint sndsock; /* send (udp) socket file descriptor */ 32218579Sfenner 32318579Sfennerstruct sockaddr whereto; /* Who to try to reach */ 324100787Sfennerstruct sockaddr wherefrom; /* Who we are */ 32518579Sfennerint packlen; /* total length of packet */ 32646542Sarchieint protlen; /* length of protocol part of packet */ 327100787Sfennerint minpacket; /* min ip packet size */ 32818579Sfennerint maxpacket = 32 * 1024; /* max ip packet size */ 329100787Sfennerint pmtu; /* Path MTU Discovery (RFC1191) */ 330100787Sfenneru_int pausemsecs; 33118579Sfenner 33218579Sfennerchar *prog; 33318579Sfennerchar *source; 33418579Sfennerchar *hostname; 335100787Sfennerchar *device; 336100787Sfennerstatic const char devnull[] = "/dev/null"; 33718579Sfenner 338163387Sdwmaloneint nprobes = -1; 33977816Sruint max_ttl; 340100787Sfennerint first_ttl = 1; 34118579Sfenneru_short ident; 34246542Sarchieu_short port; /* protocol specific base "port" */ 34318579Sfenner 34418579Sfennerint options; /* socket options */ 34518579Sfennerint verbose; 34618579Sfennerint waittime = 5; /* time to wait for response (in seconds) */ 34718579Sfennerint nflag; /* print addresses numerically */ 348176428Srpauloint as_path; /* print as numbers for each hop */ 349176428Srpaulochar *as_server = NULL; 350176428Srpaulovoid *asn; 351100787Sfenner#ifdef CANT_HACK_IPCKSUM 352100787Sfennerint doipcksum = 0; /* don't calculate ip checksums by default */ 353100787Sfenner#else 354100787Sfennerint doipcksum = 1; /* calculate ip checksums by default */ 355100787Sfenner#endif 356100787Sfennerint optlen; /* length of ip options */ 357158424Scjcint fixedPort = 0; /* Use fixed destination port for TCP and UDP */ 358163387Sdwmaloneint printdiff = 0; /* Print the difference between sent and quoted */ 35918579Sfenner 36018579Sfennerextern int optind; 36118579Sfennerextern int opterr; 36218579Sfennerextern char *optarg; 36318579Sfenner 36418579Sfenner/* Forwards */ 36518579Sfennerdouble deltaT(struct timeval *, struct timeval *); 366100787Sfennervoid freehostinfo(struct hostinfo *); 367100787Sfennervoid getaddr(u_int32_t *, char *); 368100787Sfennerstruct hostinfo *gethostinfo(char *); 369100535Sfenneru_short in_cksum(u_short *, int); 37018579Sfennerchar *inetname(struct in_addr); 37118579Sfennerint main(int, char **); 372100789Sfenneru_short p_cksum(struct ip *, u_short *, int); 37318579Sfennerint packet_ok(u_char *, int, struct sockaddr_in *, int); 37418579Sfennerchar *pr_type(u_char); 37518579Sfennervoid print(u_char *, int, struct sockaddr_in *); 37658804Sshin#ifdef IPSEC 37758804Sshinint setpolicy __P((int so, char *policy)); 37858804Sshin#endif 37946542Sarchievoid send_probe(int, int); 380100787Sfennerstruct outproto *setproto(char *); 381100787Sfennerint str2val(const char *, const char *, int, int); 38218579Sfennervoid tvsub(struct timeval *, struct timeval *); 38367682Sobrienvoid usage(void); 384100787Sfennerint wait_for_reply(int, struct sockaddr_in *, const struct timeval *); 385163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int); 386100787Sfenner#ifndef HAVE_USLEEP 387100787Sfennerint usleep(u_int); 388100787Sfenner#endif 38918579Sfenner 39046542Sarchievoid udp_prep(struct outdata *); 39146542Sarchieint udp_check(const u_char *, int); 39246542Sarchievoid tcp_prep(struct outdata *); 39346542Sarchieint tcp_check(const u_char *, int); 39446542Sarchievoid gre_prep(struct outdata *); 39546542Sarchieint gre_check(const u_char *, int); 39646542Sarchievoid gen_prep(struct outdata *); 39746542Sarchieint gen_check(const u_char *, int); 398100535Sfennervoid icmp_prep(struct outdata *); 399100535Sfennerint icmp_check(const u_char *, int); 40046542Sarchie 401100787Sfenner/* Descriptor structure for each outgoing protocol we support */ 402100787Sfennerstruct outproto { 403100787Sfenner char *name; /* name of protocol */ 404163387Sdwmalone const char *key; /* An ascii key for the bytes of the header */ 405100787Sfenner u_char num; /* IP protocol number */ 406100787Sfenner u_short hdrlen; /* max size of protocol header */ 407100787Sfenner u_short port; /* default base protocol-specific "port" */ 408100787Sfenner void (*prepare)(struct outdata *); 409100787Sfenner /* finish preparing an outgoing packet */ 410100787Sfenner int (*check)(const u_char *, int); 411100787Sfenner /* check an incoming packet */ 412100787Sfenner}; 413100787Sfenner 41446542Sarchie/* List of supported protocols. The first one is the default. The last 41546542Sarchie one is the handler for generic protocols not explicitly listed. */ 41646542Sarchiestruct outproto protos[] = { 41746542Sarchie { 41846542Sarchie "udp", 419163387Sdwmalone "spt dpt len sum", 42046542Sarchie IPPROTO_UDP, 42146542Sarchie sizeof(struct udphdr), 42246542Sarchie 32768 + 666, 42346542Sarchie udp_prep, 42446542Sarchie udp_check 42546542Sarchie }, 42646542Sarchie { 42746542Sarchie "tcp", 428163387Sdwmalone "spt dpt seq ack xxflwin sum urp", 42946542Sarchie IPPROTO_TCP, 43046542Sarchie sizeof(struct tcphdr), 43146542Sarchie 32768 + 666, 43246542Sarchie tcp_prep, 43346542Sarchie tcp_check 43446542Sarchie }, 43546542Sarchie { 43646542Sarchie "gre", 437163387Sdwmalone "flg pro len clid", 43846542Sarchie IPPROTO_GRE, 43946542Sarchie sizeof(struct grehdr), 44046542Sarchie GRE_PPTP_PROTO, 44146542Sarchie gre_prep, 44246542Sarchie gre_check 44346542Sarchie }, 44446542Sarchie { 445100535Sfenner "icmp", 446163387Sdwmalone "typ cod sum ", 447100535Sfenner IPPROTO_ICMP, 448100535Sfenner sizeof(struct icmp), 449100535Sfenner 0, 450100535Sfenner icmp_prep, 451100535Sfenner icmp_check 452100535Sfenner }, 453100535Sfenner { 45446542Sarchie NULL, 455163387Sdwmalone NULL, 45646542Sarchie 0, 45746542Sarchie 2 * sizeof(u_short), 45846542Sarchie 0, 45946542Sarchie gen_prep, 46046542Sarchie gen_check 46146542Sarchie }, 46246542Sarchie}; 46346542Sarchiestruct outproto *proto = &protos[0]; 46446542Sarchie 465163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts"; 466163387Sdwmalone 46718579Sfennerint 46818579Sfennermain(int argc, char **argv) 46918579Sfenner{ 470100787Sfenner register int op, code, n; 47118579Sfenner register char *cp; 472100787Sfenner register const char *err; 473100787Sfenner register u_int32_t *ap; 474100787Sfenner register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; 47518579Sfenner register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; 476100787Sfenner register struct hostinfo *hi; 47718579Sfenner int on = 1; 47818579Sfenner register struct protoent *pe; 47918579Sfenner register int ttl, probe, i; 48018579Sfenner register int seq = 0; 481100787Sfenner int tos = 0, settos = 0; 48218579Sfenner register int lsrr = 0; 483100787Sfenner register u_short off = 0; 484100787Sfenner struct ifaddrlist *al; 485100787Sfenner char errbuf[132]; 48648221Sarchie int requestPort = -1; 48718803Ssef int sump = 0; 48818583Sfenner int sockerrno; 48918579Sfenner 490100787Sfenner /* Insure the socket fds won't be 0, 1 or 2 */ 491100787Sfenner if (open(devnull, O_RDONLY) < 0 || 492100787Sfenner open(devnull, O_RDONLY) < 0 || 493100787Sfenner open(devnull, O_RDONLY) < 0) { 494100787Sfenner Fprintf(stderr, "%s: open \"%s\": %s\n", 495100787Sfenner prog, devnull, strerror(errno)); 496100787Sfenner exit(1); 497100787Sfenner } 49818583Sfenner /* 49918583Sfenner * Do the setuid-required stuff first, then lose priveleges ASAP. 50018583Sfenner * Do error checking for these two calls where they appeared in 50118583Sfenner * the original code. 50218583Sfenner */ 50318583Sfenner cp = "icmp"; 50418583Sfenner pe = getprotobyname(cp); 50518583Sfenner if (pe) { 50618583Sfenner if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) 50718583Sfenner sockerrno = errno; 50818583Sfenner else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 50918583Sfenner sockerrno = errno; 51018583Sfenner } 51118583Sfenner 51218583Sfenner setuid(getuid()); 51318583Sfenner 51477816Sru#ifdef IPCTL_DEFTTL 51577816Sru { 51677816Sru int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; 51777816Sru size_t sz = sizeof(max_ttl); 51877816Sru 519100787Sfenner if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) { 520100787Sfenner perror("sysctl(net.inet.ip.ttl)"); 521100787Sfenner exit(1); 522100787Sfenner } 52377816Sru } 52477816Sru#else 52577816Sru max_ttl = 30; 52677816Sru#endif 52777816Sru 528100787Sfenner if (argv[0] == NULL) 529100787Sfenner prog = "traceroute"; 530100787Sfenner else if ((cp = strrchr(argv[0], '/')) != NULL) 53118579Sfenner prog = cp + 1; 53218579Sfenner else 53318579Sfenner prog = argv[0]; 53418579Sfenner 53518579Sfenner opterr = 0; 536176428Srpaulo while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF) 53718579Sfenner switch (op) { 538176428Srpaulo case 'a': 539176428Srpaulo as_path = 1; 540176428Srpaulo break; 541176428Srpaulo 542176428Srpaulo case 'A': 543176428Srpaulo as_path = 1; 544176428Srpaulo as_server = optarg; 545176428Srpaulo break; 546176428Srpaulo 54718579Sfenner case 'd': 54818579Sfenner options |= SO_DEBUG; 54918579Sfenner break; 55018579Sfenner 551163387Sdwmalone case 'D': 552163387Sdwmalone printdiff = 1; 553163387Sdwmalone break; 554163387Sdwmalone 555158424Scjc case 'e': 556158424Scjc fixedPort = 1; 557158424Scjc break; 558158424Scjc 559100787Sfenner case 'f': 560100787Sfenner case 'M': /* FreeBSD compat. */ 561100787Sfenner first_ttl = str2val(optarg, "first ttl", 1, 255); 562100787Sfenner break; 563100787Sfenner 564100787Sfenner case 'F': 565100787Sfenner off = IP_DF; 566100787Sfenner break; 567100787Sfenner 56818579Sfenner case 'g': 56918579Sfenner if (lsrr >= NGATEWAYS) { 57018579Sfenner Fprintf(stderr, 57118579Sfenner "%s: No more than %d gateways\n", 57218579Sfenner prog, NGATEWAYS); 57318579Sfenner exit(1); 57418579Sfenner } 575100787Sfenner getaddr(gwlist + lsrr, optarg); 57618579Sfenner ++lsrr; 57718579Sfenner break; 57818579Sfenner 579100787Sfenner case 'i': 580100787Sfenner device = optarg; 58147071Sarchie break; 58247071Sarchie 583100787Sfenner case 'I': 584100787Sfenner proto = setproto("icmp"); 585100787Sfenner break; 586100787Sfenner 58718579Sfenner case 'm': 588100787Sfenner max_ttl = str2val(optarg, "max ttl", 1, 255); 58918579Sfenner break; 59018579Sfenner 59118579Sfenner case 'n': 59218579Sfenner ++nflag; 59318579Sfenner break; 59418579Sfenner 59546542Sarchie case 'P': 596100787Sfenner proto = setproto(optarg); 59746542Sarchie break; 59846542Sarchie 59918579Sfenner case 'p': 600100787Sfenner requestPort = (u_short)str2val(optarg, "port", 601100787Sfenner 1, (1 << 16) - 1); 60218579Sfenner break; 60318579Sfenner 60418579Sfenner case 'q': 605100787Sfenner nprobes = str2val(optarg, "nprobes", 1, -1); 60618579Sfenner break; 60718579Sfenner 60818579Sfenner case 'r': 60918579Sfenner options |= SO_DONTROUTE; 61018579Sfenner break; 61118579Sfenner 61218579Sfenner case 's': 61318579Sfenner /* 61418579Sfenner * set the ip source address of the outbound 61518579Sfenner * probe (e.g., on a multi-homed host). 61618579Sfenner */ 61718579Sfenner source = optarg; 61818579Sfenner break; 61918579Sfenner 620100787Sfenner case 'S': 621100787Sfenner sump = 1; 622100787Sfenner break; 623100787Sfenner 62418579Sfenner case 't': 625100787Sfenner tos = str2val(optarg, "tos", 0, 255); 626100787Sfenner ++settos; 62718579Sfenner break; 62818579Sfenner 62918579Sfenner case 'v': 63018579Sfenner ++verbose; 63118579Sfenner break; 63218579Sfenner 633100787Sfenner case 'x': 634100787Sfenner doipcksum = (doipcksum == 0); 635100787Sfenner break; 636100787Sfenner 63718579Sfenner case 'w': 638100787Sfenner waittime = str2val(optarg, "wait time", 639169144Smaxim 1, 24 * 60 * 60); 64018579Sfenner break; 64118579Sfenner 642100787Sfenner case 'z': 643100787Sfenner pausemsecs = str2val(optarg, "pause msecs", 644100787Sfenner 0, 60 * 60 * 1000); 645100787Sfenner break; 646100787Sfenner 64718579Sfenner default: 64818579Sfenner usage(); 64918579Sfenner } 65018579Sfenner 65148221Sarchie /* Set requested port, if any, else default for this protocol */ 65248221Sarchie port = (requestPort != -1) ? requestPort : proto->port; 65348221Sarchie 654163387Sdwmalone if (nprobes == -1) 655163387Sdwmalone nprobes = printdiff ? 1 : 3; 656163387Sdwmalone 657100787Sfenner if (first_ttl > max_ttl) { 658100787Sfenner Fprintf(stderr, 659100787Sfenner "%s: first ttl (%d) may not be greater than max ttl (%d)\n", 660100787Sfenner prog, first_ttl, max_ttl); 66147071Sarchie exit(1); 66247071Sarchie } 66347071Sarchie 664100787Sfenner if (!doipcksum) 665100787Sfenner Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog); 666100787Sfenner 667100787Sfenner if (lsrr > 0) 668100787Sfenner optlen = (lsrr + 1) * sizeof(gwlist[0]); 669100787Sfenner minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen; 670100787Sfenner packlen = minpacket; /* minimum sized packet */ 671100787Sfenner 67218579Sfenner /* Process destination and optional packet size */ 67318579Sfenner switch (argc - optind) { 67418579Sfenner 67518579Sfenner case 2: 676100787Sfenner packlen = str2val(argv[optind + 1], 677100787Sfenner "packet length", minpacket, maxpacket); 678100787Sfenner /* Fall through */ 67918579Sfenner 68018579Sfenner case 1: 681100787Sfenner hostname = argv[optind]; 682100787Sfenner hi = gethostinfo(hostname); 683100787Sfenner setsin(to, hi->addrs[0]); 684100787Sfenner if (hi->n > 1) 685100787Sfenner Fprintf(stderr, 686100787Sfenner "%s: Warning: %s has multiple addresses; using %s\n", 687100787Sfenner prog, hostname, inet_ntoa(to->sin_addr)); 688100787Sfenner hostname = hi->name; 689100787Sfenner hi->name = NULL; 690100787Sfenner freehostinfo(hi); 69118579Sfenner break; 69218579Sfenner 69318579Sfenner default: 69418579Sfenner usage(); 69518579Sfenner } 69618579Sfenner 69718579Sfenner#ifdef HAVE_SETLINEBUF 69818579Sfenner setlinebuf (stdout); 69918579Sfenner#else 70018579Sfenner setvbuf(stdout, NULL, _IOLBF, 0); 70118579Sfenner#endif 70218579Sfenner 70346542Sarchie protlen = packlen - sizeof(*outip) - optlen; 70418579Sfenner 70518579Sfenner outip = (struct ip *)malloc((unsigned)packlen); 70618579Sfenner if (outip == NULL) { 70718579Sfenner Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); 70818579Sfenner exit(1); 70918579Sfenner } 71018579Sfenner memset((char *)outip, 0, packlen); 71118579Sfenner 71218579Sfenner outip->ip_v = IPVERSION; 713100787Sfenner if (settos) 714100787Sfenner outip->ip_tos = tos; 715100787Sfenner#ifdef BYTESWAP_IP_HDR 71618579Sfenner outip->ip_len = htons(packlen); 717100787Sfenner outip->ip_off = htons(off); 71818579Sfenner#else 71918579Sfenner outip->ip_len = packlen; 720100787Sfenner outip->ip_off = off; 72118579Sfenner#endif 72246542Sarchie outip->ip_p = proto->num; 723100787Sfenner outp = (u_char *)(outip + 1); 72418579Sfenner#ifdef HAVE_RAW_OPTIONS 72518579Sfenner if (lsrr > 0) { 72618579Sfenner register u_char *optlist; 72718579Sfenner 728100787Sfenner optlist = outp; 729100787Sfenner outp += optlen; 73018579Sfenner 73118579Sfenner /* final hop */ 73218579Sfenner gwlist[lsrr] = to->sin_addr.s_addr; 73318579Sfenner 73418579Sfenner outip->ip_dst.s_addr = gwlist[0]; 73518579Sfenner 73618579Sfenner /* force 4 byte alignment */ 73718579Sfenner optlist[0] = IPOPT_NOP; 73818579Sfenner /* loose source route option */ 73918579Sfenner optlist[1] = IPOPT_LSRR; 74018579Sfenner i = lsrr * sizeof(gwlist[0]); 74118579Sfenner optlist[2] = i + 3; 74218579Sfenner /* Pointer to LSRR addresses */ 74318579Sfenner optlist[3] = IPOPT_MINOFF; 74418579Sfenner memcpy(optlist + 4, gwlist + 1, i); 74518579Sfenner } else 74618579Sfenner#endif 74718579Sfenner outip->ip_dst = to->sin_addr; 74818579Sfenner 749100787Sfenner outip->ip_hl = (outp - (u_char *)outip) >> 2; 75018579Sfenner ident = (getpid() & 0xffff) | 0x8000; 75118579Sfenner 75218583Sfenner if (pe == NULL) { 75318579Sfenner Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 75418579Sfenner exit(1); 75518579Sfenner } 75618583Sfenner if (s < 0) { 75718583Sfenner errno = sockerrno; 75818579Sfenner Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); 75918579Sfenner exit(1); 76018579Sfenner } 76118579Sfenner if (options & SO_DEBUG) 76218579Sfenner (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, 76318579Sfenner sizeof(on)); 76418579Sfenner if (options & SO_DONTROUTE) 76518579Sfenner (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 76618579Sfenner sizeof(on)); 76718579Sfenner 76858804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 76958804Sshin if (setpolicy(s, "in bypass") < 0) 77066809Skris errx(1, "%s", ipsec_strerror()); 77158804Sshin 77258804Sshin if (setpolicy(s, "out bypass") < 0) 77366809Skris errx(1, "%s", ipsec_strerror()); 77458804Sshin#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ 77558804Sshin 77618583Sfenner if (sndsock < 0) { 77718583Sfenner errno = sockerrno; 77818579Sfenner Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); 77918579Sfenner exit(1); 78018579Sfenner } 78118579Sfenner 78218579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) 78318579Sfenner if (lsrr > 0) { 78418579Sfenner u_char optlist[MAX_IPOPTLEN]; 78518579Sfenner 78618579Sfenner cp = "ip"; 78718579Sfenner if ((pe = getprotobyname(cp)) == NULL) { 78818579Sfenner Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 78918579Sfenner exit(1); 79018579Sfenner } 79118579Sfenner 79218579Sfenner /* final hop */ 79318579Sfenner gwlist[lsrr] = to->sin_addr.s_addr; 79418579Sfenner ++lsrr; 79518579Sfenner 79618579Sfenner /* force 4 byte alignment */ 79718579Sfenner optlist[0] = IPOPT_NOP; 79818579Sfenner /* loose source route option */ 79918579Sfenner optlist[1] = IPOPT_LSRR; 80018579Sfenner i = lsrr * sizeof(gwlist[0]); 80118579Sfenner optlist[2] = i + 3; 80218579Sfenner /* Pointer to LSRR addresses */ 80318579Sfenner optlist[3] = IPOPT_MINOFF; 80418579Sfenner memcpy(optlist + 4, gwlist, i); 80518579Sfenner 806100787Sfenner if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, 807100787Sfenner (char *)optlist, i + sizeof(gwlist[0]))) < 0) { 80818579Sfenner Fprintf(stderr, "%s: IP_OPTIONS: %s\n", 80918579Sfenner prog, strerror(errno)); 81018579Sfenner exit(1); 81118579Sfenner } 81218579Sfenner } 81318579Sfenner#endif 81418579Sfenner 81518579Sfenner#ifdef SO_SNDBUF 81618579Sfenner if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, 81718579Sfenner sizeof(packlen)) < 0) { 81818579Sfenner Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno)); 81918579Sfenner exit(1); 82018579Sfenner } 82118579Sfenner#endif 82218579Sfenner#ifdef IP_HDRINCL 82318579Sfenner if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 82418579Sfenner sizeof(on)) < 0) { 82518579Sfenner Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); 82618579Sfenner exit(1); 82718579Sfenner } 828100787Sfenner#else 829100787Sfenner#ifdef IP_TOS 830100787Sfenner if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, 831100787Sfenner (char *)&tos, sizeof(tos)) < 0) { 832100787Sfenner Fprintf(stderr, "%s: setsockopt tos %d: %s\n", 833100787Sfenner prog, tos, strerror(errno)); 834100787Sfenner exit(1); 835100787Sfenner } 83618579Sfenner#endif 837100787Sfenner#endif 83818579Sfenner if (options & SO_DEBUG) 83918579Sfenner (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, 84018579Sfenner sizeof(on)); 84118579Sfenner if (options & SO_DONTROUTE) 84218579Sfenner (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 84318579Sfenner sizeof(on)); 84418579Sfenner 845100787Sfenner /* Get the interface address list */ 846100787Sfenner n = ifaddrlist(&al, errbuf); 847100787Sfenner if (n < 0) { 848100787Sfenner Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); 849100787Sfenner exit(1); 850100787Sfenner } 851100787Sfenner if (n == 0) { 852100787Sfenner Fprintf(stderr, 853100787Sfenner "%s: Can't find any network interfaces\n", prog); 854100787Sfenner exit(1); 855100787Sfenner } 856100787Sfenner 857100787Sfenner /* Look for a specific device */ 858100787Sfenner if (device != NULL) { 859100787Sfenner for (i = n; i > 0; --i, ++al) 860100787Sfenner if (strcmp(device, al->device) == 0) 861100787Sfenner break; 862100787Sfenner if (i <= 0) { 863100787Sfenner Fprintf(stderr, "%s: Can't find interface %.32s\n", 864100787Sfenner prog, device); 865100787Sfenner exit(1); 86618579Sfenner } 86718579Sfenner } 86818579Sfenner 869100787Sfenner /* Determine our source address */ 870100787Sfenner if (source == NULL) { 871100787Sfenner /* 872100787Sfenner * If a device was specified, use the interface address. 873100787Sfenner * Otherwise, try to determine our source address. 874100787Sfenner */ 875100787Sfenner if (device != NULL) 876100787Sfenner setsin(from, al->addr); 877100787Sfenner else if ((err = findsaddr(to, from)) != NULL) { 878100787Sfenner Fprintf(stderr, "%s: findsaddr: %s\n", 879100787Sfenner prog, err); 880100787Sfenner exit(1); 881100787Sfenner } 882100787Sfenner } else { 883100787Sfenner hi = gethostinfo(source); 884100787Sfenner source = hi->name; 885100787Sfenner hi->name = NULL; 886100787Sfenner /* 887100787Sfenner * If the device was specified make sure it 888100787Sfenner * corresponds to the source address specified. 889100787Sfenner * Otherwise, use the first address (and warn if 890100787Sfenner * there are more than one). 891100787Sfenner */ 892100787Sfenner if (device != NULL) { 893100787Sfenner for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) 894100787Sfenner if (*ap == al->addr) 895100787Sfenner break; 896100787Sfenner if (i <= 0) { 897100787Sfenner Fprintf(stderr, 898100787Sfenner "%s: %s is not on interface %.32s\n", 899100787Sfenner prog, source, device); 900100787Sfenner exit(1); 901100787Sfenner } 902100787Sfenner setsin(from, *ap); 903100787Sfenner } else { 904100787Sfenner setsin(from, hi->addrs[0]); 905100787Sfenner if (hi->n > 1) 906100787Sfenner Fprintf(stderr, 907100787Sfenner "%s: Warning: %s has multiple addresses; using %s\n", 908100787Sfenner prog, source, inet_ntoa(from->sin_addr)); 909100787Sfenner } 910100787Sfenner freehostinfo(hi); 911100787Sfenner } 912100787Sfenner 913100787Sfenner outip->ip_src = from->sin_addr; 914128365Spb 915128365Spb /* Check the source address (-s), if any, is valid */ 916100787Sfenner if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { 917100787Sfenner Fprintf(stderr, "%s: bind: %s\n", 918100787Sfenner prog, strerror(errno)); 919100787Sfenner exit (1); 920100787Sfenner } 921100787Sfenner 922176428Srpaulo if (as_path) { 923176428Srpaulo asn = as_setup(as_server); 924176428Srpaulo if (asn == NULL) { 925176428Srpaulo Fprintf(stderr, "%s: as_setup failed, AS# lookups" 926176428Srpaulo " disabled\n", prog); 927176428Srpaulo (void)fflush(stderr); 928176428Srpaulo as_path = 0; 929176428Srpaulo } 930176428Srpaulo } 931176428Srpaulo 93258804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 93358804Sshin if (setpolicy(sndsock, "in bypass") < 0) 93466809Skris errx(1, "%s", ipsec_strerror()); 93558804Sshin 93658804Sshin if (setpolicy(sndsock, "out bypass") < 0) 93766809Skris errx(1, "%s", ipsec_strerror()); 93858804Sshin#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ 93958804Sshin 94018579Sfenner Fprintf(stderr, "%s to %s (%s)", 94118579Sfenner prog, hostname, inet_ntoa(to->sin_addr)); 94218579Sfenner if (source) 94318579Sfenner Fprintf(stderr, " from %s", source); 94418579Sfenner Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); 94518579Sfenner (void)fflush(stderr); 94618579Sfenner 947100787Sfenner for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 94818579Sfenner u_int32_t lastaddr = 0; 949100787Sfenner int gotlastaddr = 0; 95018579Sfenner int got_there = 0; 95118579Sfenner int unreachable = 0; 952100787Sfenner int sentfirst = 0; 95318695Ssef int loss; 95418579Sfenner 95518579Sfenner Printf("%2d ", ttl); 95618695Ssef for (probe = 0, loss = 0; probe < nprobes; ++probe) { 95718579Sfenner register int cc; 95818579Sfenner struct timeval t1, t2; 95918579Sfenner register struct ip *ip; 96046542Sarchie struct outdata outdata; 96118579Sfenner 962100787Sfenner if (sentfirst && pausemsecs > 0) 963100787Sfenner usleep(pausemsecs * 1000); 96446542Sarchie /* Prepare outgoing data */ 96546542Sarchie outdata.seq = ++seq; 96646542Sarchie outdata.ttl = ttl; 96746542Sarchie 96846542Sarchie /* Avoid alignment problems by copying bytewise: */ 969211062Sed (void)gettimeofday(&t1, NULL); 97046542Sarchie memcpy(&outdata.tv, &t1, sizeof(outdata.tv)); 97146542Sarchie 97246542Sarchie /* Finalize and send packet */ 97346542Sarchie (*proto->prepare)(&outdata); 97446542Sarchie send_probe(seq, ttl); 975100787Sfenner ++sentfirst; 97646542Sarchie 97746542Sarchie /* Wait for a reply */ 978100787Sfenner while ((cc = wait_for_reply(s, from, &t1)) != 0) { 97918583Sfenner double T; 98018583Sfenner int precis; 98118583Sfenner 982211062Sed (void)gettimeofday(&t2, NULL); 983100787Sfenner i = packet_ok(packet, cc, from, seq); 98418579Sfenner /* Skip short packet */ 98518579Sfenner if (i == 0) 98618579Sfenner continue; 987100787Sfenner if (!gotlastaddr || 988100787Sfenner from->sin_addr.s_addr != lastaddr) { 989154192Spav if (gotlastaddr) printf("\n "); 990100787Sfenner print(packet, cc, from); 991100787Sfenner lastaddr = from->sin_addr.s_addr; 992100787Sfenner ++gotlastaddr; 99318579Sfenner } 99418583Sfenner T = deltaT(&t1, &t2); 99518583Sfenner#ifdef SANE_PRECISION 99618583Sfenner if (T >= 1000.0) 99718583Sfenner precis = 0; 99818583Sfenner else if (T >= 100.0) 99918583Sfenner precis = 1; 100018583Sfenner else if (T >= 10.0) 100118583Sfenner precis = 2; 100218583Sfenner else 100318583Sfenner#endif 100418583Sfenner precis = 3; 100518583Sfenner Printf(" %.*f ms", precis, T); 1006163387Sdwmalone if (printdiff) { 1007163387Sdwmalone Printf("\n"); 1008163387Sdwmalone Printf("%*.*s%s\n", 1009163387Sdwmalone -(outip->ip_hl << 3), 1010163387Sdwmalone outip->ip_hl << 3, 1011163387Sdwmalone ip_hdr_key, 1012163387Sdwmalone proto->key); 1013163387Sdwmalone pkt_compare((void *)outip, packlen, 1014163387Sdwmalone (void *)hip, hiplen); 1015163387Sdwmalone } 1016100535Sfenner if (i == -2) { 1017100567Sdcs#ifndef ARCHAIC 1018100535Sfenner ip = (struct ip *)packet; 1019100535Sfenner if (ip->ip_ttl <= 1) 1020100535Sfenner Printf(" !"); 1021100535Sfenner#endif 1022100535Sfenner ++got_there; 1023100535Sfenner break; 1024100535Sfenner } 102518579Sfenner /* time exceeded in transit */ 102618579Sfenner if (i == -1) 102718579Sfenner break; 102818579Sfenner code = i - 1; 102918579Sfenner switch (code) { 103018579Sfenner 103118579Sfenner case ICMP_UNREACH_PORT: 103218579Sfenner#ifndef ARCHAIC 103318579Sfenner ip = (struct ip *)packet; 103418579Sfenner if (ip->ip_ttl <= 1) 103518579Sfenner Printf(" !"); 103618579Sfenner#endif 103718579Sfenner ++got_there; 103818579Sfenner break; 103918579Sfenner 104018579Sfenner case ICMP_UNREACH_NET: 104118579Sfenner ++unreachable; 104218579Sfenner Printf(" !N"); 104318579Sfenner break; 104418579Sfenner 104518579Sfenner case ICMP_UNREACH_HOST: 104618579Sfenner ++unreachable; 104718579Sfenner Printf(" !H"); 104818579Sfenner break; 104918579Sfenner 105018579Sfenner case ICMP_UNREACH_PROTOCOL: 105118579Sfenner ++got_there; 105218579Sfenner Printf(" !P"); 105318579Sfenner break; 105418579Sfenner 105518579Sfenner case ICMP_UNREACH_NEEDFRAG: 105618579Sfenner ++unreachable; 1057100787Sfenner Printf(" !F-%d", pmtu); 105818579Sfenner break; 105918579Sfenner 106018579Sfenner case ICMP_UNREACH_SRCFAIL: 106118579Sfenner ++unreachable; 106218579Sfenner Printf(" !S"); 106318579Sfenner break; 106418579Sfenner 1065159576Sdwmalone case ICMP_UNREACH_NET_UNKNOWN: 1066159576Sdwmalone ++unreachable; 1067159576Sdwmalone Printf(" !U"); 1068159576Sdwmalone break; 1069159576Sdwmalone 1070159576Sdwmalone case ICMP_UNREACH_HOST_UNKNOWN: 1071159576Sdwmalone ++unreachable; 1072159576Sdwmalone Printf(" !W"); 1073159576Sdwmalone break; 1074159576Sdwmalone 1075159576Sdwmalone case ICMP_UNREACH_ISOLATED: 1076159576Sdwmalone ++unreachable; 1077159576Sdwmalone Printf(" !I"); 1078159576Sdwmalone break; 1079159576Sdwmalone 1080159576Sdwmalone case ICMP_UNREACH_NET_PROHIB: 1081159576Sdwmalone ++unreachable; 1082159576Sdwmalone Printf(" !A"); 1083159576Sdwmalone break; 1084159576Sdwmalone 1085159576Sdwmalone case ICMP_UNREACH_HOST_PROHIB: 1086159576Sdwmalone ++unreachable; 1087159576Sdwmalone Printf(" !Z"); 1088159576Sdwmalone break; 1089159576Sdwmalone 1090159576Sdwmalone case ICMP_UNREACH_TOSNET: 1091159576Sdwmalone ++unreachable; 1092159576Sdwmalone Printf(" !Q"); 1093159576Sdwmalone break; 1094159576Sdwmalone 1095159576Sdwmalone case ICMP_UNREACH_TOSHOST: 1096159576Sdwmalone ++unreachable; 1097159576Sdwmalone Printf(" !T"); 1098159576Sdwmalone break; 1099159576Sdwmalone 110018579Sfenner case ICMP_UNREACH_FILTER_PROHIB: 110118579Sfenner ++unreachable; 110218579Sfenner Printf(" !X"); 110318579Sfenner break; 110418579Sfenner 1105100787Sfenner case ICMP_UNREACH_HOST_PRECEDENCE: 1106100787Sfenner ++unreachable; 1107100787Sfenner Printf(" !V"); 1108100787Sfenner break; 1109100787Sfenner 1110100787Sfenner case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1111100787Sfenner ++unreachable; 1112100787Sfenner Printf(" !C"); 1113100787Sfenner break; 1114100787Sfenner 111518579Sfenner default: 111618579Sfenner ++unreachable; 111718579Sfenner Printf(" !<%d>", code); 111818579Sfenner break; 111918579Sfenner } 112018579Sfenner break; 112118579Sfenner } 112218695Ssef if (cc == 0) { 112318695Ssef loss++; 112418579Sfenner Printf(" *"); 112518695Ssef } 112618579Sfenner (void)fflush(stdout); 112718579Sfenner } 112818803Ssef if (sump) { 112918811Ssef Printf(" (%d%% loss)", (loss * 100) / nprobes); 113018803Ssef } 113118579Sfenner putchar('\n'); 113218579Sfenner if (got_there || 113318579Sfenner (unreachable > 0 && unreachable >= nprobes - 1)) 113418579Sfenner break; 113518579Sfenner } 1136176428Srpaulo if (as_path) 1137176428Srpaulo as_shutdown(asn); 113818579Sfenner exit(0); 113918579Sfenner} 114018579Sfenner 114118579Sfennerint 114218579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp, 1143100787Sfenner register const struct timeval *tp) 114418579Sfenner{ 114566810Skris fd_set *fdsp; 114666810Skris size_t nfds; 114718579Sfenner struct timeval now, wait; 114818579Sfenner register int cc = 0; 114944086Sdes register int error; 115018579Sfenner int fromlen = sizeof(*fromp); 115118579Sfenner 115266810Skris nfds = howmany(sock + 1, NFDBITS); 115398709Srobert if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL) 115466810Skris err(1, "malloc"); 115598709Srobert memset(fdsp, 0, nfds * sizeof(fd_mask)); 115666810Skris FD_SET(sock, fdsp); 115718579Sfenner 115818579Sfenner wait.tv_sec = tp->tv_sec + waittime; 115918579Sfenner wait.tv_usec = tp->tv_usec; 1160211062Sed (void)gettimeofday(&now, NULL); 116118579Sfenner tvsub(&wait, &now); 116244086Sdes if (wait.tv_sec < 0) { 116344086Sdes wait.tv_sec = 0; 116444086Sdes wait.tv_usec = 1; 116544086Sdes } 116618579Sfenner 116766810Skris error = select(sock + 1, fdsp, NULL, NULL, &wait); 116844086Sdes if (error == -1 && errno == EINVAL) { 116944086Sdes Fprintf(stderr, "%s: botched select() args\n", prog); 117044086Sdes exit(1); 117144086Sdes } 117244086Sdes if (error > 0) 1173100787Sfenner cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, 117418579Sfenner (struct sockaddr *)fromp, &fromlen); 117518579Sfenner 117666810Skris free(fdsp); 117718579Sfenner return(cc); 117818579Sfenner} 117918579Sfenner 1180100787Sfennervoid 1181100787Sfennersend_probe(int seq, int ttl) 1182100787Sfenner{ 1183100787Sfenner register int cc; 1184100787Sfenner 1185100787Sfenner outip->ip_ttl = ttl; 1186100787Sfenner outip->ip_id = htons(ident + seq); 1187100787Sfenner 1188100787Sfenner /* XXX undocumented debugging hack */ 1189100787Sfenner if (verbose > 1) { 1190100787Sfenner register const u_short *sp; 1191100787Sfenner register int nshorts, i; 1192100787Sfenner 1193100787Sfenner sp = (u_short *)outip; 1194100787Sfenner nshorts = (u_int)packlen / sizeof(u_short); 1195100787Sfenner i = 0; 1196100787Sfenner Printf("[ %d bytes", packlen); 1197100787Sfenner while (--nshorts >= 0) { 1198100787Sfenner if ((i++ % 8) == 0) 1199100787Sfenner Printf("\n\t"); 1200100787Sfenner Printf(" %04x", ntohs(*sp++)); 1201100787Sfenner } 1202100787Sfenner if (packlen & 1) { 1203100787Sfenner if ((i % 8) == 0) 1204100787Sfenner Printf("\n\t"); 1205100787Sfenner Printf(" %02x", *(u_char *)sp); 1206100787Sfenner } 1207100787Sfenner Printf("]\n"); 1208100787Sfenner } 1209100787Sfenner 1210100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL) 1211100787Sfenner if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, 1212100787Sfenner (char *)&ttl, sizeof(ttl)) < 0) { 1213100787Sfenner Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", 1214100787Sfenner prog, ttl, strerror(errno)); 1215100787Sfenner exit(1); 1216100787Sfenner } 1217100787Sfenner#endif 1218100787Sfenner 1219100787Sfenner cc = sendto(sndsock, (char *)outip, 1220100787Sfenner packlen, 0, &whereto, sizeof(whereto)); 1221100787Sfenner if (cc < 0 || cc != packlen) { 1222100787Sfenner if (cc < 0) 1223100787Sfenner Fprintf(stderr, "%s: sendto: %s\n", 1224100787Sfenner prog, strerror(errno)); 1225100787Sfenner Printf("%s: wrote %s %d chars, ret=%d\n", 1226100787Sfenner prog, hostname, packlen, cc); 1227100787Sfenner (void)fflush(stdout); 1228100787Sfenner } 1229100787Sfenner} 1230100787Sfenner 123158804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 123258804Sshinint 123358804Sshinsetpolicy(so, policy) 123458804Sshin int so; 123558804Sshin char *policy; 123658804Sshin{ 123758804Sshin char *buf; 123858804Sshin 123958804Sshin buf = ipsec_set_policy(policy, strlen(policy)); 124058804Sshin if (buf == NULL) { 124166809Skris warnx("%s", ipsec_strerror()); 124258804Sshin return -1; 124358804Sshin } 124458804Sshin (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY, 124558804Sshin buf, ipsec_get_policylen(buf)); 124658804Sshin 124758804Sshin free(buf); 124858804Sshin 124958804Sshin return 0; 125058804Sshin} 125158804Sshin#endif 125258804Sshin 125318579Sfennerdouble 125418579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p) 125518579Sfenner{ 125618579Sfenner register double dt; 125718579Sfenner 125818579Sfenner dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 125918579Sfenner (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 126018579Sfenner return (dt); 126118579Sfenner} 126218579Sfenner 126318579Sfenner/* 126418579Sfenner * Convert an ICMP "type" field to a printable string. 126518579Sfenner */ 126618579Sfennerchar * 126718579Sfennerpr_type(register u_char t) 126818579Sfenner{ 126918579Sfenner static char *ttab[] = { 127018579Sfenner "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 127118579Sfenner "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 127218579Sfenner "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 127318579Sfenner "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 127418579Sfenner "Info Reply" 127518579Sfenner }; 127618579Sfenner 127718579Sfenner if (t > 16) 127818579Sfenner return("OUT-OF-RANGE"); 127918579Sfenner 128018579Sfenner return(ttab[t]); 128118579Sfenner} 128218579Sfenner 128318579Sfennerint 128418579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from, 128518579Sfenner register int seq) 128618579Sfenner{ 128718579Sfenner register struct icmp *icp; 128818579Sfenner register u_char type, code; 128918579Sfenner register int hlen; 129018579Sfenner#ifndef ARCHAIC 129118579Sfenner register struct ip *ip; 129218579Sfenner 129318579Sfenner ip = (struct ip *) buf; 129418579Sfenner hlen = ip->ip_hl << 2; 129518579Sfenner if (cc < hlen + ICMP_MINLEN) { 129618579Sfenner if (verbose) 129718579Sfenner Printf("packet too short (%d bytes) from %s\n", cc, 129818579Sfenner inet_ntoa(from->sin_addr)); 129918579Sfenner return (0); 130018579Sfenner } 130118579Sfenner cc -= hlen; 130218579Sfenner icp = (struct icmp *)(buf + hlen); 130318579Sfenner#else 130418579Sfenner icp = (struct icmp *)buf; 130518579Sfenner#endif 130618579Sfenner type = icp->icmp_type; 130718579Sfenner code = icp->icmp_code; 1308100787Sfenner /* Path MTU Discovery (RFC1191) */ 1309100787Sfenner if (code != ICMP_UNREACH_NEEDFRAG) 1310100787Sfenner pmtu = 0; 1311100787Sfenner else { 1312100787Sfenner#ifdef HAVE_ICMP_NEXTMTU 1313100787Sfenner pmtu = ntohs(icp->icmp_nextmtu); 1314100787Sfenner#else 1315100787Sfenner pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu); 1316100787Sfenner#endif 1317100787Sfenner } 1318100535Sfenner if (type == ICMP_ECHOREPLY 1319100535Sfenner && proto->num == IPPROTO_ICMP 1320124859Scperciva && (*proto->check)((u_char *)icp, (u_char)seq)) 1321100535Sfenner return -2; 132218579Sfenner if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 132318579Sfenner type == ICMP_UNREACH) { 132446542Sarchie u_char *inner; 132518579Sfenner 132618579Sfenner hip = &icp->icmp_ip; 1327163387Sdwmalone hiplen = ((u_char *)icp + cc) - (u_char *)hip; 132818579Sfenner hlen = hip->ip_hl << 2; 132946542Sarchie inner = (u_char *)((u_char *)hip + hlen); 133046542Sarchie if (hlen + 12 <= cc 133146542Sarchie && hip->ip_p == proto->num 1332124859Scperciva && (*proto->check)(inner, (u_char)seq)) 133318579Sfenner return (type == ICMP_TIMXCEED ? -1 : code + 1); 133418579Sfenner } 133518579Sfenner#ifndef ARCHAIC 133618579Sfenner if (verbose) { 133718579Sfenner register int i; 133818579Sfenner u_int32_t *lp = (u_int32_t *)&icp->icmp_ip; 133918579Sfenner 134018579Sfenner Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr)); 134118579Sfenner Printf("%s: icmp type %d (%s) code %d\n", 134218579Sfenner inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); 134318579Sfenner for (i = 4; i < cc ; i += sizeof(*lp)) 134418579Sfenner Printf("%2d: x%8.8x\n", i, *lp++); 134518579Sfenner } 134618579Sfenner#endif 134718579Sfenner return(0); 134818579Sfenner} 134918579Sfenner 135046542Sarchievoid 1351100535Sfennericmp_prep(struct outdata *outdata) 1352100535Sfenner{ 1353100787Sfenner struct icmp *const icmpheader = (struct icmp *) outp; 1354100535Sfenner 1355100535Sfenner icmpheader->icmp_type = ICMP_ECHO; 1356100535Sfenner icmpheader->icmp_id = htons(ident); 1357100535Sfenner icmpheader->icmp_seq = htons(outdata->seq); 1358100535Sfenner icmpheader->icmp_cksum = 0; 1359100789Sfenner icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen); 1360100535Sfenner if (icmpheader->icmp_cksum == 0) 1361100535Sfenner icmpheader->icmp_cksum = 0xffff; 1362100535Sfenner} 1363100535Sfenner 1364100535Sfennerint 1365100535Sfennericmp_check(const u_char *data, int seq) 1366100535Sfenner{ 1367100535Sfenner struct icmp *const icmpheader = (struct icmp *) data; 1368100535Sfenner 1369100535Sfenner return (icmpheader->icmp_id == htons(ident) 1370100535Sfenner && icmpheader->icmp_seq == htons(seq)); 1371100535Sfenner} 1372100535Sfenner 1373100535Sfennervoid 137446542Sarchieudp_prep(struct outdata *outdata) 137546542Sarchie{ 1376100787Sfenner struct udphdr *const outudp = (struct udphdr *) outp; 137718579Sfenner 1378158424Scjc outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0)); 1379158424Scjc outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1380100787Sfenner outudp->uh_ulen = htons((u_short)protlen); 1381100789Sfenner outudp->uh_sum = 0; 1382100787Sfenner if (doipcksum) { 1383100789Sfenner u_short sum = p_cksum(outip, (u_short*)outudp, protlen); 1384100789Sfenner outudp->uh_sum = (sum) ? sum : 0xffff; 1385100787Sfenner } 1386100789Sfenner 1387100789Sfenner return; 138846542Sarchie} 138946542Sarchie 139046542Sarchieint 139146542Sarchieudp_check(const u_char *data, int seq) 139246542Sarchie{ 139346542Sarchie struct udphdr *const udp = (struct udphdr *) data; 139446542Sarchie 1395158424Scjc return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) && 1396158424Scjc ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq)); 139746542Sarchie} 139846542Sarchie 139918579Sfennervoid 140046542Sarchietcp_prep(struct outdata *outdata) 140146542Sarchie{ 1402100787Sfenner struct tcphdr *const tcp = (struct tcphdr *) outp; 140346542Sarchie 140446542Sarchie tcp->th_sport = htons(ident); 1405158424Scjc tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1406158424Scjc tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport + 1407158424Scjc (fixedPort ? outdata->seq : 0)); 140846542Sarchie tcp->th_ack = 0; 140946542Sarchie tcp->th_off = 5; 141046542Sarchie tcp->th_flags = TH_SYN; 1411100789Sfenner tcp->th_sum = 0; 1412100789Sfenner 1413100789Sfenner if (doipcksum) { 1414100789Sfenner u_short sum = p_cksum(outip, (u_short*)tcp, protlen); 1415100789Sfenner tcp->th_sum = (sum) ? sum : 0xffff; 1416100789Sfenner } 141746542Sarchie} 141846542Sarchie 141946542Sarchieint 142046542Sarchietcp_check(const u_char *data, int seq) 142146542Sarchie{ 142246542Sarchie struct tcphdr *const tcp = (struct tcphdr *) data; 142346542Sarchie 142446542Sarchie return (ntohs(tcp->th_sport) == ident 1425158424Scjc && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq)) 1426216184Suqs && tcp->th_seq == (((tcp_seq)ident << 16) | (port + seq)); 142746542Sarchie} 142846542Sarchie 142946542Sarchievoid 143046542Sarchiegre_prep(struct outdata *outdata) 143146542Sarchie{ 1432100787Sfenner struct grehdr *const gre = (struct grehdr *) outp; 143346542Sarchie 143446542Sarchie gre->flags = htons(0x2001); 143546542Sarchie gre->proto = htons(port); 143646542Sarchie gre->length = 0; 143746542Sarchie gre->callId = htons(ident + outdata->seq); 143846542Sarchie} 143946542Sarchie 144046542Sarchieint 144146542Sarchiegre_check(const u_char *data, int seq) 144246542Sarchie{ 144346542Sarchie struct grehdr *const gre = (struct grehdr *) data; 144446542Sarchie 144546542Sarchie return(ntohs(gre->proto) == port 144646542Sarchie && ntohs(gre->callId) == ident + seq); 144746542Sarchie} 144846542Sarchie 144946542Sarchievoid 145046542Sarchiegen_prep(struct outdata *outdata) 145146542Sarchie{ 1452100787Sfenner u_int16_t *const ptr = (u_int16_t *) outp; 145346542Sarchie 145446542Sarchie ptr[0] = htons(ident); 145546542Sarchie ptr[1] = htons(port + outdata->seq); 145646542Sarchie} 145746542Sarchie 145846542Sarchieint 145946542Sarchiegen_check(const u_char *data, int seq) 146046542Sarchie{ 146146542Sarchie u_int16_t *const ptr = (u_int16_t *) data; 146246542Sarchie 146346542Sarchie return(ntohs(ptr[0]) == ident 146446542Sarchie && ntohs(ptr[1]) == port + seq); 146546542Sarchie} 146646542Sarchie 146746542Sarchievoid 146818579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from) 146918579Sfenner{ 147018579Sfenner register struct ip *ip; 147118579Sfenner register int hlen; 1472196475Sume char addr[INET_ADDRSTRLEN]; 147318579Sfenner 147418579Sfenner ip = (struct ip *) buf; 147518579Sfenner hlen = ip->ip_hl << 2; 147618579Sfenner cc -= hlen; 147718579Sfenner 1478196475Sume strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr)); 1479196475Sume 1480176428Srpaulo if (as_path) 1481196475Sume Printf(" [AS%u]", as_lookup(asn, addr, AF_INET)); 1482176428Srpaulo 148318579Sfenner if (nflag) 1484196475Sume Printf(" %s", addr); 148518579Sfenner else 1486196475Sume Printf(" %s (%s)", inetname(from->sin_addr), addr); 148718579Sfenner 148818579Sfenner if (verbose) 148918579Sfenner Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 149018579Sfenner} 149118579Sfenner 149218579Sfenner/* 1493100789Sfenner * Checksum routine for UDP and TCP headers. 1494100789Sfenner */ 1495100789Sfenneru_short 1496100789Sfennerp_cksum(struct ip *ip, u_short *data, int len) 1497100789Sfenner{ 1498100789Sfenner static struct ipovly ipo; 1499216184Suqs u_short sum[2]; 1500100789Sfenner 1501100789Sfenner ipo.ih_pr = ip->ip_p; 1502100789Sfenner ipo.ih_len = htons(len); 1503100789Sfenner ipo.ih_src = ip->ip_src; 1504100789Sfenner ipo.ih_dst = ip->ip_dst; 1505100789Sfenner 1506216184Suqs sum[1] = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */ 1507216184Suqs sum[0] = in_cksum(data, len); /* payload data cksum */ 1508100789Sfenner 1509216184Suqs return ~in_cksum(sum, sizeof(sum)); 1510100789Sfenner} 1511100789Sfenner 1512100789Sfenner/* 151318579Sfenner * Checksum routine for Internet Protocol family headers (C Version) 151418579Sfenner */ 1515100535Sfenneru_short 151618579Sfennerin_cksum(register u_short *addr, register int len) 151718579Sfenner{ 151818579Sfenner register int nleft = len; 151918579Sfenner register u_short *w = addr; 152018579Sfenner register u_short answer; 152118579Sfenner register int sum = 0; 152218579Sfenner 152318579Sfenner /* 152418579Sfenner * Our algorithm is simple, using a 32 bit accumulator (sum), 152518579Sfenner * we add sequential 16 bit words to it, and at the end, fold 152618579Sfenner * back all the carry bits from the top 16 bits into the lower 152718579Sfenner * 16 bits. 152818579Sfenner */ 152918579Sfenner while (nleft > 1) { 153018579Sfenner sum += *w++; 153118579Sfenner nleft -= 2; 153218579Sfenner } 153318579Sfenner 153418579Sfenner /* mop up an odd byte, if necessary */ 153518579Sfenner if (nleft == 1) 153618579Sfenner sum += *(u_char *)w; 153718579Sfenner 153818579Sfenner /* 153918579Sfenner * add back carry outs from top 16 bits to low 16 bits 154018579Sfenner */ 154118579Sfenner sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 154218579Sfenner sum += (sum >> 16); /* add carry */ 154318579Sfenner answer = ~sum; /* truncate to 16 bits */ 154418579Sfenner return (answer); 154518579Sfenner} 154618579Sfenner 154718579Sfenner/* 154818579Sfenner * Subtract 2 timeval structs: out = out - in. 154944086Sdes * Out is assumed to be within about LONG_MAX seconds of in. 155018579Sfenner */ 155118579Sfennervoid 155218579Sfennertvsub(register struct timeval *out, register struct timeval *in) 155318579Sfenner{ 155418579Sfenner 155518579Sfenner if ((out->tv_usec -= in->tv_usec) < 0) { 155618579Sfenner --out->tv_sec; 155718579Sfenner out->tv_usec += 1000000; 155818579Sfenner } 155918579Sfenner out->tv_sec -= in->tv_sec; 156018579Sfenner} 156118579Sfenner 156218579Sfenner/* 156318579Sfenner * Construct an Internet address representation. 156418579Sfenner * If the nflag has been supplied, give 156518579Sfenner * numeric value, otherwise try for symbolic name. 156618579Sfenner */ 156718579Sfennerchar * 156818579Sfennerinetname(struct in_addr in) 156918579Sfenner{ 157018579Sfenner register char *cp; 157118579Sfenner register struct hostent *hp; 157218579Sfenner static int first = 1; 157318579Sfenner static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1]; 157418579Sfenner 157518579Sfenner if (first && !nflag) { 157618579Sfenner first = 0; 1577100787Sfenner if (gethostname(domain, sizeof(domain) - 1) < 0) 157818579Sfenner domain[0] = '\0'; 1579100787Sfenner else { 1580100787Sfenner cp = strchr(domain, '.'); 1581100787Sfenner if (cp == NULL) { 1582100787Sfenner hp = gethostbyname(domain); 1583100787Sfenner if (hp != NULL) 1584100787Sfenner cp = strchr(hp->h_name, '.'); 1585100787Sfenner } 1586100787Sfenner if (cp == NULL) 1587100787Sfenner domain[0] = '\0'; 1588100787Sfenner else { 1589100787Sfenner ++cp; 1590100787Sfenner (void)strncpy(domain, cp, sizeof(domain) - 1); 1591100787Sfenner domain[sizeof(domain) - 1] = '\0'; 1592100787Sfenner } 1593100787Sfenner } 159418579Sfenner } 159518579Sfenner if (!nflag && in.s_addr != INADDR_ANY) { 159618579Sfenner hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); 159718579Sfenner if (hp != NULL) { 159818579Sfenner if ((cp = strchr(hp->h_name, '.')) != NULL && 159918579Sfenner strcmp(cp + 1, domain) == 0) 160018579Sfenner *cp = '\0'; 160118579Sfenner (void)strncpy(line, hp->h_name, sizeof(line) - 1); 160218579Sfenner line[sizeof(line) - 1] = '\0'; 160318579Sfenner return (line); 160418579Sfenner } 160518579Sfenner } 160618579Sfenner return (inet_ntoa(in)); 160718579Sfenner} 160818579Sfenner 1609100787Sfennerstruct hostinfo * 1610100787Sfennergethostinfo(register char *hostname) 161118579Sfenner{ 1612100787Sfenner register int n; 161318579Sfenner register struct hostent *hp; 1614100787Sfenner register struct hostinfo *hi; 1615100787Sfenner register char **p; 1616100787Sfenner register u_int32_t addr, *ap; 161718579Sfenner 1618100787Sfenner if (strlen(hostname) > 64) { 1619100787Sfenner Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", 1620100787Sfenner prog, hostname); 1621100787Sfenner exit(1); 1622100787Sfenner } 1623100787Sfenner hi = calloc(1, sizeof(*hi)); 1624100787Sfenner if (hi == NULL) { 1625100787Sfenner Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1626100787Sfenner exit(1); 1627100787Sfenner } 1628100787Sfenner addr = inet_addr(hostname); 1629100787Sfenner if ((int32_t)addr != -1) { 1630100787Sfenner hi->name = strdup(hostname); 1631100787Sfenner hi->n = 1; 1632100787Sfenner hi->addrs = calloc(1, sizeof(hi->addrs[0])); 1633100787Sfenner if (hi->addrs == NULL) { 1634100787Sfenner Fprintf(stderr, "%s: calloc %s\n", 1635100787Sfenner prog, strerror(errno)); 1636100787Sfenner exit(1); 1637100787Sfenner } 1638100787Sfenner hi->addrs[0] = addr; 1639100787Sfenner return (hi); 1640100787Sfenner } 164118579Sfenner 164218579Sfenner hp = gethostbyname(hostname); 164318579Sfenner if (hp == NULL) { 164418579Sfenner Fprintf(stderr, "%s: unknown host %s\n", prog, hostname); 164518579Sfenner exit(1); 164618579Sfenner } 164718579Sfenner if (hp->h_addrtype != AF_INET || hp->h_length != 4) { 164818579Sfenner Fprintf(stderr, "%s: bad host %s\n", prog, hostname); 164918579Sfenner exit(1); 165018579Sfenner } 1651100787Sfenner hi->name = strdup(hp->h_name); 1652100787Sfenner for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) 1653100787Sfenner continue; 1654100787Sfenner hi->n = n; 1655100787Sfenner hi->addrs = calloc(n, sizeof(hi->addrs[0])); 1656100787Sfenner if (hi->addrs == NULL) { 1657100787Sfenner Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1658100787Sfenner exit(1); 1659100787Sfenner } 1660100787Sfenner for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) 1661100787Sfenner memcpy(ap, *p, sizeof(*ap)); 1662100787Sfenner return (hi); 166318579Sfenner} 166418579Sfenner 1665100787Sfennervoid 1666100787Sfennerfreehostinfo(register struct hostinfo *hi) 166718579Sfenner{ 1668100787Sfenner if (hi->name != NULL) { 1669100787Sfenner free(hi->name); 1670100787Sfenner hi->name = NULL; 1671100787Sfenner } 1672100787Sfenner free((char *)hi->addrs); 1673100787Sfenner free((char *)hi); 1674100787Sfenner} 167518579Sfenner 1676100787Sfennervoid 1677100787Sfennergetaddr(register u_int32_t *ap, register char *hostname) 1678100787Sfenner{ 1679100787Sfenner register struct hostinfo *hi; 1680100787Sfenner 1681100787Sfenner hi = gethostinfo(hostname); 1682100787Sfenner *ap = hi->addrs[0]; 1683100787Sfenner freehostinfo(hi); 1684100787Sfenner} 1685100787Sfenner 1686100787Sfennervoid 1687100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr) 1688100787Sfenner{ 1689100787Sfenner 169018579Sfenner memset(sin, 0, sizeof(*sin)); 1691100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN 1692100787Sfenner sin->sin_len = sizeof(*sin); 1693100787Sfenner#endif 169418579Sfenner sin->sin_family = AF_INET; 1695100787Sfenner sin->sin_addr.s_addr = addr; 169618579Sfenner} 169718579Sfenner 1698100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */ 1699100787Sfennerint 1700100787Sfennerstr2val(register const char *str, register const char *what, 1701100787Sfenner register int mi, register int ma) 170218579Sfenner{ 1703100787Sfenner register const char *cp; 1704100787Sfenner register int val; 1705100787Sfenner char *ep; 170618579Sfenner 1707100787Sfenner if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 1708100787Sfenner cp = str + 2; 1709100787Sfenner val = (int)strtol(cp, &ep, 16); 1710100787Sfenner } else 1711100787Sfenner val = (int)strtol(str, &ep, 10); 1712100787Sfenner if (*ep != '\0') { 1713100787Sfenner Fprintf(stderr, "%s: \"%s\" bad value for %s \n", 1714100787Sfenner prog, str, what); 171518579Sfenner exit(1); 171618579Sfenner } 1717100787Sfenner if (val < mi && mi >= 0) { 1718100787Sfenner if (mi == 0) 1719100787Sfenner Fprintf(stderr, "%s: %s must be >= %d\n", 1720100787Sfenner prog, what, mi); 1721100787Sfenner else 1722100787Sfenner Fprintf(stderr, "%s: %s must be > %d\n", 1723100787Sfenner prog, what, mi - 1); 1724100787Sfenner exit(1); 1725100787Sfenner } 1726100787Sfenner if (val > ma && ma >= 0) { 1727100787Sfenner Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); 1728100787Sfenner exit(1); 1729100787Sfenner } 1730100787Sfenner return (val); 173118579Sfenner} 173218579Sfenner 1733100787Sfennerstruct outproto * 1734100787Sfennersetproto(char *pname) 1735100787Sfenner{ 1736100787Sfenner struct outproto *proto; 1737100787Sfenner int i; 1738100787Sfenner 1739100787Sfenner for (i = 0; protos[i].name != NULL; i++) { 1740100787Sfenner if (strcasecmp(protos[i].name, pname) == 0) { 1741100787Sfenner break; 1742100787Sfenner } 1743100787Sfenner } 1744100787Sfenner proto = &protos[i]; 1745100787Sfenner if (proto->name == NULL) { /* generic handler */ 1746100787Sfenner struct protoent *pe; 1747100787Sfenner u_long pnum; 1748100787Sfenner 1749100787Sfenner /* Determine the IP protocol number */ 1750100787Sfenner if ((pe = getprotobyname(pname)) != NULL) 1751100787Sfenner pnum = pe->p_proto; 1752100787Sfenner else 1753100787Sfenner pnum = str2val(optarg, "proto number", 1, 255); 1754100787Sfenner proto->num = pnum; 1755100787Sfenner } 1756100787Sfenner return proto; 1757100787Sfenner} 1758100787Sfenner 175967682Sobrienvoid 1760163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) { 1761163387Sdwmalone int l; 1762163387Sdwmalone int i; 1763163387Sdwmalone 1764163387Sdwmalone for (i = 0; i < la; i++) 1765163387Sdwmalone Printf("%02x", (unsigned int)a[i]); 1766163387Sdwmalone Printf("\n"); 1767163387Sdwmalone l = (la <= lb) ? la : lb; 1768163387Sdwmalone for (i = 0; i < l; i++) 1769163387Sdwmalone if (a[i] == b[i]) 1770163387Sdwmalone Printf("__"); 1771163387Sdwmalone else 1772163387Sdwmalone Printf("%02x", (unsigned int)b[i]); 1773163387Sdwmalone for (; i < lb; i++) 1774163387Sdwmalone Printf("%02x", (unsigned int)b[i]); 1775163387Sdwmalone Printf("\n"); 1776163387Sdwmalone} 1777163387Sdwmalone 1778163387Sdwmalone 1779163387Sdwmalonevoid 178018579Sfennerusage(void) 178118579Sfenner{ 178218579Sfenner extern char version[]; 178318579Sfenner 178418579Sfenner Fprintf(stderr, "Version %s\n", version); 1785100787Sfenner Fprintf(stderr, 1786176428Srpaulo "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n" 1787100787Sfenner "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n" 1788176428Srpaulo "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog); 178918579Sfenner exit(1); 179018579Sfenner} 1791