118579Sfenner/* 2100787Sfenner * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000 318579Sfenner * The Regents of the University of California. All rights reserved. 418579Sfenner * 518579Sfenner * Redistribution and use in source and binary forms, with or without 618579Sfenner * modification, are permitted provided that: (1) source code distributions 718579Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 818579Sfenner * distributions including binary code include the above copyright notice and 918579Sfenner * this paragraph in its entirety in the documentation or other materials 1018579Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1118579Sfenner * features or use of this software display the following acknowledgement: 1218579Sfenner * ``This product includes software developed by the University of California, 1318579Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1418579Sfenner * the University nor the names of its contributors may be used to endorse 1518579Sfenner * or promote products derived from this software without specific prior 1618579Sfenner * written permission. 1718579Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1818579Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1918579Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2018579Sfenner */ 2118579Sfenner 2218579Sfenner#ifndef lint 2318579Sfennerstatic const char copyright[] = 24100787Sfenner "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\ 2518579SfennerThe Regents of the University of California. All rights reserved.\n"; 2658835Sshin#if 0 2718579Sfennerstatic const char rcsid[] = 28100787Sfenner "@(#)$Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp $ (LBL)"; 2918579Sfenner#endif 3058835Sshinstatic const char rcsid[] = 3158835Sshin "$FreeBSD$"; 3258835Sshin#endif 3318579Sfenner 3418579Sfenner/* 3518579Sfenner * traceroute host - trace the route ip packets follow going to "host". 3618579Sfenner * 3718579Sfenner * Attempt to trace the route an ip packet would follow to some 3818579Sfenner * internet host. We find out intermediate hops by launching probe 3918579Sfenner * packets with a small ttl (time to live) then listening for an 4018579Sfenner * icmp "time exceeded" reply from a gateway. We start our probes 4118579Sfenner * with a ttl of one and increase by one until we get an icmp "port 4218579Sfenner * unreachable" (which means we got to "host") or hit a max (which 4377816Sru * defaults to net.inet.ip.ttl hops & can be changed with the -m flag). 4477816Sru * Three probes (change with -q flag) are sent at each ttl setting and 4577816Sru * a line is printed showing the ttl, address of the gateway and 4618579Sfenner * round trip time of each probe. If the probe answers come from 4718579Sfenner * different gateways, the address of each responding system will 4818579Sfenner * be printed. If there is no response within a 5 sec. timeout 4918579Sfenner * interval (changed with the -w flag), a "*" is printed for that 5018579Sfenner * probe. 5118579Sfenner * 5218579Sfenner * Probe packets are UDP format. We don't want the destination 5318579Sfenner * host to process them so the destination port is set to an 5418579Sfenner * unlikely value (if some clod on the destination is using that 5518579Sfenner * value, it can be changed with the -p flag). 5618579Sfenner * 5718579Sfenner * A sample use might be: 5818579Sfenner * 5918579Sfenner * [yak 71]% traceroute nis.nsf.net. 6077816Sru * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet 6118579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 6218579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 6318579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 6418579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 6518579Sfenner * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 6618579Sfenner * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 6718579Sfenner * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 6818579Sfenner * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 6918579Sfenner * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 7018579Sfenner * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 7118579Sfenner * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 7218579Sfenner * 7318579Sfenner * Note that lines 2 & 3 are the same. This is due to a buggy 7418579Sfenner * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 7518579Sfenner * packets with a zero ttl. 7618579Sfenner * 7718579Sfenner * A more interesting example is: 7818579Sfenner * 7918579Sfenner * [yak 72]% traceroute allspice.lcs.mit.edu. 8077816Sru * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max 8118579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 8218579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 8318579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 8418579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 8518579Sfenner * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 8618579Sfenner * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 8718579Sfenner * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 8818579Sfenner * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 8918579Sfenner * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 9018579Sfenner * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 9118579Sfenner * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 9218579Sfenner * 12 * * * 9318579Sfenner * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 9418579Sfenner * 14 * * * 9518579Sfenner * 15 * * * 9618579Sfenner * 16 * * * 9718579Sfenner * 17 * * * 9818579Sfenner * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 9918579Sfenner * 10018579Sfenner * (I start to see why I'm having so much trouble with mail to 10118579Sfenner * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 10218579Sfenner * either don't send ICMP "time exceeded" messages or send them 10318579Sfenner * with a ttl too small to reach us. 14 - 17 are running the 10418579Sfenner * MIT C Gateway code that doesn't send "time exceeded"s. God 10518579Sfenner * only knows what's going on with 12. 10618579Sfenner * 10718579Sfenner * The silent gateway 12 in the above may be the result of a bug in 10818579Sfenner * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 10918579Sfenner * sends an unreachable message using whatever ttl remains in the 11018579Sfenner * original datagram. Since, for gateways, the remaining ttl is 11118579Sfenner * zero, the icmp "time exceeded" is guaranteed to not make it back 11218579Sfenner * to us. The behavior of this bug is slightly more interesting 11318579Sfenner * when it appears on the destination system: 11418579Sfenner * 11518579Sfenner * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 11618579Sfenner * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 11718579Sfenner * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 11818579Sfenner * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 11918579Sfenner * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 12018579Sfenner * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 12118579Sfenner * 7 * * * 12218579Sfenner * 8 * * * 12318579Sfenner * 9 * * * 12418579Sfenner * 10 * * * 12518579Sfenner * 11 * * * 12618579Sfenner * 12 * * * 12718579Sfenner * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 12818579Sfenner * 12918579Sfenner * Notice that there are 12 "gateways" (13 is the final 13018579Sfenner * destination) and exactly the last half of them are "missing". 13118579Sfenner * What's really happening is that rip (a Sun-3 running Sun OS3.5) 13218579Sfenner * is using the ttl from our arriving datagram as the ttl in its 13318579Sfenner * icmp reply. So, the reply will time out on the return path 13418579Sfenner * (with no notice sent to anyone since icmp's aren't sent for 13518579Sfenner * icmp's) until we probe with a ttl that's at least twice the path 13618579Sfenner * length. I.e., rip is really only 7 hops away. A reply that 13718579Sfenner * returns with a ttl of 1 is a clue this problem exists. 13818579Sfenner * Traceroute prints a "!" after the time if the ttl is <= 1. 13918579Sfenner * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 14018579Sfenner * non-standard (HPUX) software, expect to see this problem 14118579Sfenner * frequently and/or take care picking the target host of your 14218579Sfenner * probes. 14318579Sfenner * 14418579Sfenner * Other possible annotations after the time are !H, !N, !P (got a host, 14518579Sfenner * network or protocol unreachable, respectively), !S or !F (source 14618579Sfenner * route failed or fragmentation needed -- neither of these should 14718579Sfenner * ever occur and the associated gateway is busted if you see one). If 14818579Sfenner * almost all the probes result in some kind of unreachable, traceroute 14918579Sfenner * will give up and exit. 15018579Sfenner * 15118579Sfenner * Notes 15218579Sfenner * ----- 15318579Sfenner * This program must be run by root or be setuid. (I suggest that 15418579Sfenner * you *don't* make it setuid -- casual use could result in a lot 15518579Sfenner * of unnecessary traffic on our poor, congested nets.) 15618579Sfenner * 15718579Sfenner * This program requires a kernel mod that does not appear in any 15818579Sfenner * system available from Berkeley: A raw ip socket using proto 15918579Sfenner * IPPROTO_RAW must interpret the data sent as an ip datagram (as 16018579Sfenner * opposed to data to be wrapped in a ip datagram). See the README 16118579Sfenner * file that came with the source to this program for a description 16218579Sfenner * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 16318579Sfenner * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 16418579Sfenner * MODIFIED TO RUN THIS PROGRAM. 16518579Sfenner * 16618579Sfenner * The udp port usage may appear bizarre (well, ok, it is bizarre). 16718579Sfenner * The problem is that an icmp message only contains 8 bytes of 16818579Sfenner * data from the original datagram. 8 bytes is the size of a udp 16918579Sfenner * header so, if we want to associate replies with the original 17018579Sfenner * datagram, the necessary information must be encoded into the 17118579Sfenner * udp header (the ip id could be used but there's no way to 17218579Sfenner * interlock with the kernel's assignment of ip id's and, anyway, 17318579Sfenner * it would have taken a lot more kernel hacking to allow this 17418579Sfenner * code to set the ip id). So, to allow two or more users to 17518579Sfenner * use traceroute simultaneously, we use this task's pid as the 17618579Sfenner * source port (the high bit is set to move the port number out 17718579Sfenner * of the "likely" range). To keep track of which probe is being 17818579Sfenner * replied to (so times and/or hop counts don't get confused by a 17918579Sfenner * reply that was delayed in transit), we increment the destination 18018579Sfenner * port number before each probe. 18118579Sfenner * 18218579Sfenner * Don't use this as a coding example. I was trying to find a 18318579Sfenner * routing problem and this code sort-of popped out after 48 hours 18418579Sfenner * without sleep. I was amazed it ever compiled, much less ran. 18518579Sfenner * 18618579Sfenner * I stole the idea for this program from Steve Deering. Since 18718579Sfenner * the first release, I've learned that had I attended the right 18818579Sfenner * IETF working group meetings, I also could have stolen it from Guy 18918579Sfenner * Almes or Matt Mathis. I don't know (or care) who came up with 19018579Sfenner * the idea first. I envy the originators' perspicacity and I'm 19118579Sfenner * glad they didn't keep the idea a secret. 19218579Sfenner * 19318579Sfenner * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 19418579Sfenner * enhancements to the original distribution. 19518579Sfenner * 19618579Sfenner * I've hacked up a round-trip-route version of this that works by 19718579Sfenner * sending a loose-source-routed udp datagram through the destination 19818579Sfenner * back to yourself. Unfortunately, SO many gateways botch source 19918579Sfenner * routing, the thing is almost worthless. Maybe one day... 20018579Sfenner * 20118579Sfenner * -- Van Jacobson (van@ee.lbl.gov) 20218579Sfenner * Tue Dec 20 03:50:13 PST 1988 20318579Sfenner */ 20418579Sfenner 20518579Sfenner#include <sys/param.h> 20618579Sfenner#include <sys/file.h> 20718579Sfenner#include <sys/ioctl.h> 20818579Sfenner#ifdef HAVE_SYS_SELECT_H 20918579Sfenner#include <sys/select.h> 21018579Sfenner#endif 21118579Sfenner#include <sys/socket.h> 21277816Sru#ifdef HAVE_SYS_SYSCTL_H 21377816Sru#include <sys/sysctl.h> 21477816Sru#endif 21518579Sfenner#include <sys/time.h> 21618579Sfenner 21718579Sfenner#include <netinet/in_systm.h> 21818579Sfenner#include <netinet/in.h> 21918579Sfenner#include <netinet/ip.h> 22018579Sfenner#include <netinet/ip_var.h> 22118579Sfenner#include <netinet/ip_icmp.h> 222283958Stuexen#include <netinet/sctp.h> 22318579Sfenner#include <netinet/udp.h> 22446542Sarchie#include <netinet/tcp.h> 225100789Sfenner#include <netinet/tcpip.h> 22618579Sfenner 22718579Sfenner#include <arpa/inet.h> 22818579Sfenner 22958804Sshin#ifdef IPSEC 23058804Sshin#include <net/route.h> 231171135Sgnn#include <netipsec/ipsec.h> /* XXX */ 23258804Sshin#endif /* IPSEC */ 23358804Sshin 23418579Sfenner#include <ctype.h> 235100787Sfenner#include <err.h> 23618579Sfenner#include <errno.h> 237100787Sfenner#include <fcntl.h> 23818579Sfenner#ifdef HAVE_MALLOC_H 23918579Sfenner#include <malloc.h> 24018579Sfenner#endif 24118579Sfenner#include <memory.h> 24218579Sfenner#include <netdb.h> 24318579Sfenner#include <stdio.h> 24418579Sfenner#include <stdlib.h> 24518579Sfenner#include <string.h> 24618579Sfenner#include <unistd.h> 24718579Sfenner 248100787Sfenner/* rfc1716 */ 249100787Sfenner#ifndef ICMP_UNREACH_FILTER_PROHIB 250100787Sfenner#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ 251100787Sfenner#endif 252100787Sfenner#ifndef ICMP_UNREACH_HOST_PRECEDENCE 253100787Sfenner#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ 254100787Sfenner#endif 255100787Sfenner#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF 256100787Sfenner#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ 257100787Sfenner#endif 258100787Sfenner 259100787Sfenner#include "findsaddr.h" 260100787Sfenner#include "ifaddrlist.h" 261176428Srpaulo#include "as.h" 262100787Sfenner#include "traceroute.h" 263100787Sfenner 26418579Sfenner/* Maximum number of gateways (include room for one noop) */ 26518579Sfenner#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) 26618579Sfenner 26718579Sfenner#ifndef MAXHOSTNAMELEN 26818579Sfenner#define MAXHOSTNAMELEN 64 26918579Sfenner#endif 27018579Sfenner 27118579Sfenner#define Fprintf (void)fprintf 27218579Sfenner#define Printf (void)printf 27318579Sfenner 27446542Sarchie/* What a GRE packet header looks like */ 27546542Sarchiestruct grehdr { 27646542Sarchie u_int16_t flags; 27746542Sarchie u_int16_t proto; 27846542Sarchie u_int16_t length; /* PPTP version of these fields */ 27946542Sarchie u_int16_t callId; 28046542Sarchie}; 28146542Sarchie#ifndef IPPROTO_GRE 28246542Sarchie#define IPPROTO_GRE 47 28346542Sarchie#endif 28446542Sarchie 28546542Sarchie/* For GRE, we prepare what looks like a PPTP packet */ 28646542Sarchie#define GRE_PPTP_PROTO 0x880b 28746542Sarchie 288100787Sfenner/* Host name and address list */ 289100787Sfennerstruct hostinfo { 290100787Sfenner char *name; 291100787Sfenner int n; 292100787Sfenner u_int32_t *addrs; 293100787Sfenner}; 294100787Sfenner 29518579Sfenner/* Data section of the probe packet */ 29618579Sfennerstruct outdata { 29718579Sfenner u_char seq; /* sequence number of this packet */ 29818579Sfenner u_char ttl; /* ttl packet left with */ 29918579Sfenner struct timeval tv; /* time packet left */ 30018579Sfenner}; 30118579Sfenner 302100787Sfenner#ifndef HAVE_ICMP_NEXTMTU 303100787Sfenner/* Path MTU Discovery (RFC1191) */ 304100787Sfennerstruct my_pmtu { 305100787Sfenner u_short ipm_void; 306100787Sfenner u_short ipm_nextmtu; 30746542Sarchie}; 308100787Sfenner#endif 30946542Sarchie 31018579Sfenneru_char packet[512]; /* last inbound (icmp) packet */ 31118579Sfenner 31246542Sarchiestruct ip *outip; /* last output ip packet */ 313100787Sfenneru_char *outp; /* last output inner protocol packet */ 31418579Sfenner 315163387Sdwmalonestruct ip *hip = NULL; /* Quoted IP header */ 316163387Sdwmaloneint hiplen = 0; 317163387Sdwmalone 31818579Sfenner/* loose source route gateway list (including room for final destination) */ 31918579Sfenneru_int32_t gwlist[NGATEWAYS + 1]; 32018579Sfenner 32118579Sfennerint s; /* receive (icmp) socket file descriptor */ 32218579Sfennerint sndsock; /* send (udp) socket file descriptor */ 32318579Sfenner 32418579Sfennerstruct sockaddr whereto; /* Who to try to reach */ 325100787Sfennerstruct sockaddr wherefrom; /* Who we are */ 32618579Sfennerint packlen; /* total length of packet */ 32746542Sarchieint protlen; /* length of protocol part of packet */ 328100787Sfennerint minpacket; /* min ip packet size */ 32918579Sfennerint maxpacket = 32 * 1024; /* max ip packet size */ 330100787Sfennerint pmtu; /* Path MTU Discovery (RFC1191) */ 331100787Sfenneru_int pausemsecs; 33218579Sfenner 33318579Sfennerchar *prog; 33418579Sfennerchar *source; 33518579Sfennerchar *hostname; 336100787Sfennerchar *device; 337100787Sfennerstatic const char devnull[] = "/dev/null"; 33818579Sfenner 339163387Sdwmaloneint nprobes = -1; 34077816Sruint max_ttl; 341100787Sfennerint first_ttl = 1; 34218579Sfenneru_short ident; 34346542Sarchieu_short port; /* protocol specific base "port" */ 34418579Sfenner 34518579Sfennerint options; /* socket options */ 34618579Sfennerint verbose; 34718579Sfennerint waittime = 5; /* time to wait for response (in seconds) */ 34818579Sfennerint nflag; /* print addresses numerically */ 349176428Srpauloint as_path; /* print as numbers for each hop */ 350176428Srpaulochar *as_server = NULL; 351176428Srpaulovoid *asn; 352100787Sfenner#ifdef CANT_HACK_IPCKSUM 353100787Sfennerint doipcksum = 0; /* don't calculate ip checksums by default */ 354100787Sfenner#else 355100787Sfennerint doipcksum = 1; /* calculate ip checksums by default */ 356100787Sfenner#endif 357100787Sfennerint optlen; /* length of ip options */ 358158424Scjcint fixedPort = 0; /* Use fixed destination port for TCP and UDP */ 359163387Sdwmaloneint printdiff = 0; /* Print the difference between sent and quoted */ 36018579Sfenner 36118579Sfennerextern int optind; 36218579Sfennerextern int opterr; 36318579Sfennerextern char *optarg; 36418579Sfenner 36518579Sfenner/* Forwards */ 36618579Sfennerdouble deltaT(struct timeval *, struct timeval *); 367100787Sfennervoid freehostinfo(struct hostinfo *); 368100787Sfennervoid getaddr(u_int32_t *, char *); 369100787Sfennerstruct hostinfo *gethostinfo(char *); 370100535Sfenneru_short in_cksum(u_short *, int); 371283958Stuexenu_int32_t sctp_crc32c(const void *, u_int32_t); 37218579Sfennerchar *inetname(struct in_addr); 37318579Sfennerint main(int, char **); 374283958Stuexenu_short p_cksum(struct ip *, u_short *, int, int); 37518579Sfennerint packet_ok(u_char *, int, struct sockaddr_in *, int); 37618579Sfennerchar *pr_type(u_char); 37718579Sfennervoid print(u_char *, int, struct sockaddr_in *); 37858804Sshin#ifdef IPSEC 37958804Sshinint setpolicy __P((int so, char *policy)); 38058804Sshin#endif 38146542Sarchievoid send_probe(int, int); 382100787Sfennerstruct outproto *setproto(char *); 383100787Sfennerint str2val(const char *, const char *, int, int); 38418579Sfennervoid tvsub(struct timeval *, struct timeval *); 38567682Sobrienvoid usage(void); 386100787Sfennerint wait_for_reply(int, struct sockaddr_in *, const struct timeval *); 387163387Sdwmalonevoid pkt_compare(const u_char *, int, const u_char *, int); 388100787Sfenner#ifndef HAVE_USLEEP 389100787Sfennerint usleep(u_int); 390100787Sfenner#endif 39118579Sfenner 39246542Sarchievoid udp_prep(struct outdata *); 39346542Sarchieint udp_check(const u_char *, int); 394283958Stuexenvoid udplite_prep(struct outdata *); 395283958Stuexenint udplite_check(const u_char *, int); 39646542Sarchievoid tcp_prep(struct outdata *); 39746542Sarchieint tcp_check(const u_char *, int); 398283958Stuexenvoid sctp_prep(struct outdata *); 399283958Stuexenint sctp_check(const u_char *, int); 40046542Sarchievoid gre_prep(struct outdata *); 40146542Sarchieint gre_check(const u_char *, int); 40246542Sarchievoid gen_prep(struct outdata *); 40346542Sarchieint gen_check(const u_char *, int); 404100535Sfennervoid icmp_prep(struct outdata *); 405100535Sfennerint icmp_check(const u_char *, int); 40646542Sarchie 407100787Sfenner/* Descriptor structure for each outgoing protocol we support */ 408100787Sfennerstruct outproto { 409100787Sfenner char *name; /* name of protocol */ 410163387Sdwmalone const char *key; /* An ascii key for the bytes of the header */ 411100787Sfenner u_char num; /* IP protocol number */ 412100787Sfenner u_short hdrlen; /* max size of protocol header */ 413100787Sfenner u_short port; /* default base protocol-specific "port" */ 414100787Sfenner void (*prepare)(struct outdata *); 415100787Sfenner /* finish preparing an outgoing packet */ 416100787Sfenner int (*check)(const u_char *, int); 417100787Sfenner /* check an incoming packet */ 418100787Sfenner}; 419100787Sfenner 42046542Sarchie/* List of supported protocols. The first one is the default. The last 42146542Sarchie one is the handler for generic protocols not explicitly listed. */ 42246542Sarchiestruct outproto protos[] = { 42346542Sarchie { 42446542Sarchie "udp", 425163387Sdwmalone "spt dpt len sum", 42646542Sarchie IPPROTO_UDP, 42746542Sarchie sizeof(struct udphdr), 42846542Sarchie 32768 + 666, 42946542Sarchie udp_prep, 43046542Sarchie udp_check 43146542Sarchie }, 43246542Sarchie { 433283958Stuexen "udplite", 434283958Stuexen "spt dpt cov sum", 435283958Stuexen IPPROTO_UDPLITE, 436283958Stuexen sizeof(struct udphdr), 437283958Stuexen 32768 + 666, 438283958Stuexen udplite_prep, 439283958Stuexen udplite_check 440283958Stuexen }, 441283958Stuexen { 44246542Sarchie "tcp", 443163387Sdwmalone "spt dpt seq ack xxflwin sum urp", 44446542Sarchie IPPROTO_TCP, 44546542Sarchie sizeof(struct tcphdr), 44646542Sarchie 32768 + 666, 44746542Sarchie tcp_prep, 44846542Sarchie tcp_check 44946542Sarchie }, 45046542Sarchie { 451283958Stuexen "sctp", 452283958Stuexen "spt dpt vtag crc tyfllen tyfllen ", 453283958Stuexen IPPROTO_SCTP, 454283958Stuexen sizeof(struct sctphdr), 455283958Stuexen 32768 + 666, 456283958Stuexen sctp_prep, 457283958Stuexen sctp_check 458283958Stuexen }, 459283958Stuexen { 46046542Sarchie "gre", 461163387Sdwmalone "flg pro len clid", 46246542Sarchie IPPROTO_GRE, 46346542Sarchie sizeof(struct grehdr), 46446542Sarchie GRE_PPTP_PROTO, 46546542Sarchie gre_prep, 46646542Sarchie gre_check 46746542Sarchie }, 46846542Sarchie { 469100535Sfenner "icmp", 470163387Sdwmalone "typ cod sum ", 471100535Sfenner IPPROTO_ICMP, 472100535Sfenner sizeof(struct icmp), 473100535Sfenner 0, 474100535Sfenner icmp_prep, 475100535Sfenner icmp_check 476100535Sfenner }, 477100535Sfenner { 47846542Sarchie NULL, 479283958Stuexen "", 48046542Sarchie 0, 48146542Sarchie 2 * sizeof(u_short), 48246542Sarchie 0, 48346542Sarchie gen_prep, 48446542Sarchie gen_check 48546542Sarchie }, 48646542Sarchie}; 48746542Sarchiestruct outproto *proto = &protos[0]; 48846542Sarchie 489163387Sdwmaloneconst char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts"; 490163387Sdwmalone 49118579Sfennerint 49218579Sfennermain(int argc, char **argv) 49318579Sfenner{ 494100787Sfenner register int op, code, n; 49518579Sfenner register char *cp; 496100787Sfenner register const char *err; 497100787Sfenner register u_int32_t *ap; 498100787Sfenner register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; 49918579Sfenner register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; 500100787Sfenner register struct hostinfo *hi; 50118579Sfenner int on = 1; 50218579Sfenner register struct protoent *pe; 50318579Sfenner register int ttl, probe, i; 50418579Sfenner register int seq = 0; 505100787Sfenner int tos = 0, settos = 0; 50618579Sfenner register int lsrr = 0; 507100787Sfenner register u_short off = 0; 508100787Sfenner struct ifaddrlist *al; 509100787Sfenner char errbuf[132]; 51048221Sarchie int requestPort = -1; 51118803Ssef int sump = 0; 51218583Sfenner int sockerrno; 51318579Sfenner 514100787Sfenner /* Insure the socket fds won't be 0, 1 or 2 */ 515100787Sfenner if (open(devnull, O_RDONLY) < 0 || 516100787Sfenner open(devnull, O_RDONLY) < 0 || 517100787Sfenner open(devnull, O_RDONLY) < 0) { 518100787Sfenner Fprintf(stderr, "%s: open \"%s\": %s\n", 519100787Sfenner prog, devnull, strerror(errno)); 520100787Sfenner exit(1); 521100787Sfenner } 52218583Sfenner /* 52318583Sfenner * Do the setuid-required stuff first, then lose priveleges ASAP. 52418583Sfenner * Do error checking for these two calls where they appeared in 52518583Sfenner * the original code. 52618583Sfenner */ 52718583Sfenner cp = "icmp"; 52818583Sfenner pe = getprotobyname(cp); 52918583Sfenner if (pe) { 53018583Sfenner if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) 53118583Sfenner sockerrno = errno; 53218583Sfenner else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 53318583Sfenner sockerrno = errno; 53418583Sfenner } 53518583Sfenner 536220968Ssimon if (setuid(getuid()) != 0) { 537220968Ssimon perror("setuid()"); 538220968Ssimon exit(1); 539220968Ssimon } 54018583Sfenner 54177816Sru#ifdef IPCTL_DEFTTL 54277816Sru { 54377816Sru int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; 54477816Sru size_t sz = sizeof(max_ttl); 54577816Sru 546100787Sfenner if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) { 547100787Sfenner perror("sysctl(net.inet.ip.ttl)"); 548100787Sfenner exit(1); 549100787Sfenner } 55077816Sru } 55177816Sru#else 55277816Sru max_ttl = 30; 55377816Sru#endif 55477816Sru 555100787Sfenner if (argv[0] == NULL) 556100787Sfenner prog = "traceroute"; 557100787Sfenner else if ((cp = strrchr(argv[0], '/')) != NULL) 55818579Sfenner prog = cp + 1; 55918579Sfenner else 56018579Sfenner prog = argv[0]; 56118579Sfenner 56218579Sfenner opterr = 0; 563176428Srpaulo while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF) 56418579Sfenner switch (op) { 565176428Srpaulo case 'a': 566176428Srpaulo as_path = 1; 567176428Srpaulo break; 568283958Stuexen 569176428Srpaulo case 'A': 570176428Srpaulo as_path = 1; 571176428Srpaulo as_server = optarg; 572176428Srpaulo break; 573283958Stuexen 57418579Sfenner case 'd': 57518579Sfenner options |= SO_DEBUG; 57618579Sfenner break; 57718579Sfenner 578163387Sdwmalone case 'D': 579163387Sdwmalone printdiff = 1; 580163387Sdwmalone break; 581163387Sdwmalone 582158424Scjc case 'e': 583158424Scjc fixedPort = 1; 584158424Scjc break; 585158424Scjc 586100787Sfenner case 'f': 587100787Sfenner case 'M': /* FreeBSD compat. */ 588100787Sfenner first_ttl = str2val(optarg, "first ttl", 1, 255); 589100787Sfenner break; 590100787Sfenner 591100787Sfenner case 'F': 592100787Sfenner off = IP_DF; 593100787Sfenner break; 594100787Sfenner 59518579Sfenner case 'g': 59618579Sfenner if (lsrr >= NGATEWAYS) { 59718579Sfenner Fprintf(stderr, 59818579Sfenner "%s: No more than %d gateways\n", 59918579Sfenner prog, NGATEWAYS); 60018579Sfenner exit(1); 60118579Sfenner } 602100787Sfenner getaddr(gwlist + lsrr, optarg); 60318579Sfenner ++lsrr; 60418579Sfenner break; 60518579Sfenner 606100787Sfenner case 'i': 607100787Sfenner device = optarg; 60847071Sarchie break; 60947071Sarchie 610100787Sfenner case 'I': 611100787Sfenner proto = setproto("icmp"); 612100787Sfenner break; 613100787Sfenner 61418579Sfenner case 'm': 615100787Sfenner max_ttl = str2val(optarg, "max ttl", 1, 255); 61618579Sfenner break; 61718579Sfenner 61818579Sfenner case 'n': 61918579Sfenner ++nflag; 62018579Sfenner break; 62118579Sfenner 62246542Sarchie case 'P': 623100787Sfenner proto = setproto(optarg); 62446542Sarchie break; 62546542Sarchie 62618579Sfenner case 'p': 627100787Sfenner requestPort = (u_short)str2val(optarg, "port", 628100787Sfenner 1, (1 << 16) - 1); 62918579Sfenner break; 63018579Sfenner 63118579Sfenner case 'q': 632100787Sfenner nprobes = str2val(optarg, "nprobes", 1, -1); 63318579Sfenner break; 63418579Sfenner 63518579Sfenner case 'r': 63618579Sfenner options |= SO_DONTROUTE; 63718579Sfenner break; 63818579Sfenner 63918579Sfenner case 's': 64018579Sfenner /* 64118579Sfenner * set the ip source address of the outbound 64218579Sfenner * probe (e.g., on a multi-homed host). 64318579Sfenner */ 64418579Sfenner source = optarg; 64518579Sfenner break; 64618579Sfenner 647100787Sfenner case 'S': 648100787Sfenner sump = 1; 649100787Sfenner break; 650100787Sfenner 65118579Sfenner case 't': 652100787Sfenner tos = str2val(optarg, "tos", 0, 255); 653100787Sfenner ++settos; 65418579Sfenner break; 65518579Sfenner 65618579Sfenner case 'v': 65718579Sfenner ++verbose; 65818579Sfenner break; 65918579Sfenner 660100787Sfenner case 'x': 661100787Sfenner doipcksum = (doipcksum == 0); 662100787Sfenner break; 663100787Sfenner 66418579Sfenner case 'w': 665100787Sfenner waittime = str2val(optarg, "wait time", 666169144Smaxim 1, 24 * 60 * 60); 66718579Sfenner break; 66818579Sfenner 669100787Sfenner case 'z': 670100787Sfenner pausemsecs = str2val(optarg, "pause msecs", 671100787Sfenner 0, 60 * 60 * 1000); 672100787Sfenner break; 673100787Sfenner 67418579Sfenner default: 67518579Sfenner usage(); 67618579Sfenner } 67718579Sfenner 67848221Sarchie /* Set requested port, if any, else default for this protocol */ 67948221Sarchie port = (requestPort != -1) ? requestPort : proto->port; 68048221Sarchie 681163387Sdwmalone if (nprobes == -1) 682163387Sdwmalone nprobes = printdiff ? 1 : 3; 683163387Sdwmalone 684100787Sfenner if (first_ttl > max_ttl) { 685100787Sfenner Fprintf(stderr, 686100787Sfenner "%s: first ttl (%d) may not be greater than max ttl (%d)\n", 687100787Sfenner prog, first_ttl, max_ttl); 68847071Sarchie exit(1); 68947071Sarchie } 69047071Sarchie 691100787Sfenner if (!doipcksum) 692100787Sfenner Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog); 693100787Sfenner 694100787Sfenner if (lsrr > 0) 695100787Sfenner optlen = (lsrr + 1) * sizeof(gwlist[0]); 696283958Stuexen minpacket = sizeof(*outip) + proto->hdrlen + optlen; 697283958Stuexen if (minpacket > 40) 698283958Stuexen packlen = minpacket; 699283958Stuexen else 700283958Stuexen packlen = 40; 701100787Sfenner 70218579Sfenner /* Process destination and optional packet size */ 70318579Sfenner switch (argc - optind) { 70418579Sfenner 70518579Sfenner case 2: 706100787Sfenner packlen = str2val(argv[optind + 1], 707100787Sfenner "packet length", minpacket, maxpacket); 708100787Sfenner /* Fall through */ 70918579Sfenner 71018579Sfenner case 1: 711100787Sfenner hostname = argv[optind]; 712100787Sfenner hi = gethostinfo(hostname); 713100787Sfenner setsin(to, hi->addrs[0]); 714100787Sfenner if (hi->n > 1) 715100787Sfenner Fprintf(stderr, 716100787Sfenner "%s: Warning: %s has multiple addresses; using %s\n", 717100787Sfenner prog, hostname, inet_ntoa(to->sin_addr)); 718100787Sfenner hostname = hi->name; 719100787Sfenner hi->name = NULL; 720100787Sfenner freehostinfo(hi); 72118579Sfenner break; 72218579Sfenner 72318579Sfenner default: 72418579Sfenner usage(); 72518579Sfenner } 72618579Sfenner 72718579Sfenner#ifdef HAVE_SETLINEBUF 72818579Sfenner setlinebuf (stdout); 72918579Sfenner#else 73018579Sfenner setvbuf(stdout, NULL, _IOLBF, 0); 73118579Sfenner#endif 73218579Sfenner 73346542Sarchie protlen = packlen - sizeof(*outip) - optlen; 734283958Stuexen if ((proto->num == IPPROTO_SCTP) && (packlen & 3)) { 735283958Stuexen Fprintf(stderr, "%s: packet length must be a multiple of 4\n", 736283958Stuexen prog); 737283958Stuexen exit(1); 738283958Stuexen } 73918579Sfenner 74018579Sfenner outip = (struct ip *)malloc((unsigned)packlen); 74118579Sfenner if (outip == NULL) { 74218579Sfenner Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); 74318579Sfenner exit(1); 74418579Sfenner } 74518579Sfenner memset((char *)outip, 0, packlen); 74618579Sfenner 74718579Sfenner outip->ip_v = IPVERSION; 748100787Sfenner if (settos) 749100787Sfenner outip->ip_tos = tos; 750100787Sfenner#ifdef BYTESWAP_IP_HDR 75118579Sfenner outip->ip_len = htons(packlen); 752100787Sfenner outip->ip_off = htons(off); 75318579Sfenner#else 75418579Sfenner outip->ip_len = packlen; 755100787Sfenner outip->ip_off = off; 75618579Sfenner#endif 75746542Sarchie outip->ip_p = proto->num; 758100787Sfenner outp = (u_char *)(outip + 1); 75918579Sfenner#ifdef HAVE_RAW_OPTIONS 76018579Sfenner if (lsrr > 0) { 76118579Sfenner register u_char *optlist; 76218579Sfenner 763100787Sfenner optlist = outp; 764100787Sfenner outp += optlen; 76518579Sfenner 76618579Sfenner /* final hop */ 76718579Sfenner gwlist[lsrr] = to->sin_addr.s_addr; 76818579Sfenner 76918579Sfenner outip->ip_dst.s_addr = gwlist[0]; 77018579Sfenner 77118579Sfenner /* force 4 byte alignment */ 77218579Sfenner optlist[0] = IPOPT_NOP; 77318579Sfenner /* loose source route option */ 77418579Sfenner optlist[1] = IPOPT_LSRR; 77518579Sfenner i = lsrr * sizeof(gwlist[0]); 77618579Sfenner optlist[2] = i + 3; 77718579Sfenner /* Pointer to LSRR addresses */ 77818579Sfenner optlist[3] = IPOPT_MINOFF; 77918579Sfenner memcpy(optlist + 4, gwlist + 1, i); 78018579Sfenner } else 78118579Sfenner#endif 78218579Sfenner outip->ip_dst = to->sin_addr; 78318579Sfenner 784100787Sfenner outip->ip_hl = (outp - (u_char *)outip) >> 2; 78518579Sfenner ident = (getpid() & 0xffff) | 0x8000; 78618579Sfenner 78718583Sfenner if (pe == NULL) { 78818579Sfenner Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 78918579Sfenner exit(1); 79018579Sfenner } 79118583Sfenner if (s < 0) { 79218583Sfenner errno = sockerrno; 79318579Sfenner Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); 79418579Sfenner exit(1); 79518579Sfenner } 79618579Sfenner if (options & SO_DEBUG) 79718579Sfenner (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, 79818579Sfenner sizeof(on)); 79918579Sfenner if (options & SO_DONTROUTE) 80018579Sfenner (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 80118579Sfenner sizeof(on)); 80218579Sfenner 80358804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 80458804Sshin if (setpolicy(s, "in bypass") < 0) 80566809Skris errx(1, "%s", ipsec_strerror()); 80658804Sshin 80758804Sshin if (setpolicy(s, "out bypass") < 0) 80866809Skris errx(1, "%s", ipsec_strerror()); 80958804Sshin#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ 81058804Sshin 81118583Sfenner if (sndsock < 0) { 81218583Sfenner errno = sockerrno; 81318579Sfenner Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); 81418579Sfenner exit(1); 81518579Sfenner } 81618579Sfenner 81718579Sfenner#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) 81818579Sfenner if (lsrr > 0) { 81918579Sfenner u_char optlist[MAX_IPOPTLEN]; 82018579Sfenner 82118579Sfenner cp = "ip"; 82218579Sfenner if ((pe = getprotobyname(cp)) == NULL) { 82318579Sfenner Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); 82418579Sfenner exit(1); 82518579Sfenner } 82618579Sfenner 82718579Sfenner /* final hop */ 82818579Sfenner gwlist[lsrr] = to->sin_addr.s_addr; 82918579Sfenner ++lsrr; 83018579Sfenner 83118579Sfenner /* force 4 byte alignment */ 83218579Sfenner optlist[0] = IPOPT_NOP; 83318579Sfenner /* loose source route option */ 83418579Sfenner optlist[1] = IPOPT_LSRR; 83518579Sfenner i = lsrr * sizeof(gwlist[0]); 83618579Sfenner optlist[2] = i + 3; 83718579Sfenner /* Pointer to LSRR addresses */ 83818579Sfenner optlist[3] = IPOPT_MINOFF; 83918579Sfenner memcpy(optlist + 4, gwlist, i); 84018579Sfenner 841100787Sfenner if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, 842100787Sfenner (char *)optlist, i + sizeof(gwlist[0]))) < 0) { 84318579Sfenner Fprintf(stderr, "%s: IP_OPTIONS: %s\n", 84418579Sfenner prog, strerror(errno)); 84518579Sfenner exit(1); 84618579Sfenner } 84718579Sfenner } 84818579Sfenner#endif 84918579Sfenner 85018579Sfenner#ifdef SO_SNDBUF 85118579Sfenner if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, 85218579Sfenner sizeof(packlen)) < 0) { 85318579Sfenner Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno)); 85418579Sfenner exit(1); 85518579Sfenner } 85618579Sfenner#endif 85718579Sfenner#ifdef IP_HDRINCL 85818579Sfenner if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 85918579Sfenner sizeof(on)) < 0) { 86018579Sfenner Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); 86118579Sfenner exit(1); 86218579Sfenner } 863100787Sfenner#else 864100787Sfenner#ifdef IP_TOS 865100787Sfenner if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, 866100787Sfenner (char *)&tos, sizeof(tos)) < 0) { 867100787Sfenner Fprintf(stderr, "%s: setsockopt tos %d: %s\n", 868100787Sfenner prog, tos, strerror(errno)); 869100787Sfenner exit(1); 870100787Sfenner } 87118579Sfenner#endif 872100787Sfenner#endif 87318579Sfenner if (options & SO_DEBUG) 87418579Sfenner (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, 87518579Sfenner sizeof(on)); 87618579Sfenner if (options & SO_DONTROUTE) 87718579Sfenner (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 87818579Sfenner sizeof(on)); 87918579Sfenner 880100787Sfenner /* Get the interface address list */ 881100787Sfenner n = ifaddrlist(&al, errbuf); 882100787Sfenner if (n < 0) { 883100787Sfenner Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); 884100787Sfenner exit(1); 885100787Sfenner } 886100787Sfenner if (n == 0) { 887100787Sfenner Fprintf(stderr, 888100787Sfenner "%s: Can't find any network interfaces\n", prog); 889100787Sfenner exit(1); 890100787Sfenner } 891100787Sfenner 892100787Sfenner /* Look for a specific device */ 893100787Sfenner if (device != NULL) { 894100787Sfenner for (i = n; i > 0; --i, ++al) 895100787Sfenner if (strcmp(device, al->device) == 0) 896100787Sfenner break; 897100787Sfenner if (i <= 0) { 898100787Sfenner Fprintf(stderr, "%s: Can't find interface %.32s\n", 899100787Sfenner prog, device); 900100787Sfenner exit(1); 90118579Sfenner } 90218579Sfenner } 90318579Sfenner 904100787Sfenner /* Determine our source address */ 905100787Sfenner if (source == NULL) { 906100787Sfenner /* 907100787Sfenner * If a device was specified, use the interface address. 908100787Sfenner * Otherwise, try to determine our source address. 909100787Sfenner */ 910100787Sfenner if (device != NULL) 911100787Sfenner setsin(from, al->addr); 912100787Sfenner else if ((err = findsaddr(to, from)) != NULL) { 913100787Sfenner Fprintf(stderr, "%s: findsaddr: %s\n", 914100787Sfenner prog, err); 915100787Sfenner exit(1); 916100787Sfenner } 917100787Sfenner } else { 918100787Sfenner hi = gethostinfo(source); 919100787Sfenner source = hi->name; 920100787Sfenner hi->name = NULL; 921100787Sfenner /* 922100787Sfenner * If the device was specified make sure it 923100787Sfenner * corresponds to the source address specified. 924100787Sfenner * Otherwise, use the first address (and warn if 925100787Sfenner * there are more than one). 926100787Sfenner */ 927100787Sfenner if (device != NULL) { 928100787Sfenner for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) 929100787Sfenner if (*ap == al->addr) 930100787Sfenner break; 931100787Sfenner if (i <= 0) { 932100787Sfenner Fprintf(stderr, 933100787Sfenner "%s: %s is not on interface %.32s\n", 934100787Sfenner prog, source, device); 935100787Sfenner exit(1); 936100787Sfenner } 937100787Sfenner setsin(from, *ap); 938100787Sfenner } else { 939100787Sfenner setsin(from, hi->addrs[0]); 940100787Sfenner if (hi->n > 1) 941100787Sfenner Fprintf(stderr, 942100787Sfenner "%s: Warning: %s has multiple addresses; using %s\n", 943100787Sfenner prog, source, inet_ntoa(from->sin_addr)); 944100787Sfenner } 945100787Sfenner freehostinfo(hi); 946100787Sfenner } 947100787Sfenner 948100787Sfenner outip->ip_src = from->sin_addr; 949128365Spb 950128365Spb /* Check the source address (-s), if any, is valid */ 951100787Sfenner if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { 952100787Sfenner Fprintf(stderr, "%s: bind: %s\n", 953100787Sfenner prog, strerror(errno)); 954100787Sfenner exit (1); 955100787Sfenner } 956100787Sfenner 957176428Srpaulo if (as_path) { 958176428Srpaulo asn = as_setup(as_server); 959176428Srpaulo if (asn == NULL) { 960176428Srpaulo Fprintf(stderr, "%s: as_setup failed, AS# lookups" 961176428Srpaulo " disabled\n", prog); 962176428Srpaulo (void)fflush(stderr); 963176428Srpaulo as_path = 0; 964176428Srpaulo } 965176428Srpaulo } 966283958Stuexen 96758804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 96858804Sshin if (setpolicy(sndsock, "in bypass") < 0) 96966809Skris errx(1, "%s", ipsec_strerror()); 97058804Sshin 97158804Sshin if (setpolicy(sndsock, "out bypass") < 0) 97266809Skris errx(1, "%s", ipsec_strerror()); 97358804Sshin#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ 97458804Sshin 97518579Sfenner Fprintf(stderr, "%s to %s (%s)", 97618579Sfenner prog, hostname, inet_ntoa(to->sin_addr)); 97718579Sfenner if (source) 97818579Sfenner Fprintf(stderr, " from %s", source); 97918579Sfenner Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); 98018579Sfenner (void)fflush(stderr); 98118579Sfenner 982100787Sfenner for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 98318579Sfenner u_int32_t lastaddr = 0; 984100787Sfenner int gotlastaddr = 0; 98518579Sfenner int got_there = 0; 98618579Sfenner int unreachable = 0; 987100787Sfenner int sentfirst = 0; 98818695Ssef int loss; 98918579Sfenner 99018579Sfenner Printf("%2d ", ttl); 99118695Ssef for (probe = 0, loss = 0; probe < nprobes; ++probe) { 99218579Sfenner register int cc; 99318579Sfenner struct timeval t1, t2; 99418579Sfenner register struct ip *ip; 99546542Sarchie struct outdata outdata; 99618579Sfenner 997100787Sfenner if (sentfirst && pausemsecs > 0) 998100787Sfenner usleep(pausemsecs * 1000); 99946542Sarchie /* Prepare outgoing data */ 100046542Sarchie outdata.seq = ++seq; 100146542Sarchie outdata.ttl = ttl; 100246542Sarchie 100346542Sarchie /* Avoid alignment problems by copying bytewise: */ 1004211062Sed (void)gettimeofday(&t1, NULL); 100546542Sarchie memcpy(&outdata.tv, &t1, sizeof(outdata.tv)); 100646542Sarchie 100746542Sarchie /* Finalize and send packet */ 100846542Sarchie (*proto->prepare)(&outdata); 100946542Sarchie send_probe(seq, ttl); 1010100787Sfenner ++sentfirst; 101146542Sarchie 101246542Sarchie /* Wait for a reply */ 1013100787Sfenner while ((cc = wait_for_reply(s, from, &t1)) != 0) { 101418583Sfenner double T; 101518583Sfenner int precis; 101618583Sfenner 1017211062Sed (void)gettimeofday(&t2, NULL); 1018100787Sfenner i = packet_ok(packet, cc, from, seq); 101918579Sfenner /* Skip short packet */ 102018579Sfenner if (i == 0) 102118579Sfenner continue; 1022100787Sfenner if (!gotlastaddr || 1023100787Sfenner from->sin_addr.s_addr != lastaddr) { 1024154192Spav if (gotlastaddr) printf("\n "); 1025100787Sfenner print(packet, cc, from); 1026100787Sfenner lastaddr = from->sin_addr.s_addr; 1027100787Sfenner ++gotlastaddr; 102818579Sfenner } 102918583Sfenner T = deltaT(&t1, &t2); 103018583Sfenner#ifdef SANE_PRECISION 103118583Sfenner if (T >= 1000.0) 103218583Sfenner precis = 0; 103318583Sfenner else if (T >= 100.0) 103418583Sfenner precis = 1; 103518583Sfenner else if (T >= 10.0) 103618583Sfenner precis = 2; 103718583Sfenner else 103818583Sfenner#endif 103918583Sfenner precis = 3; 104018583Sfenner Printf(" %.*f ms", precis, T); 1041163387Sdwmalone if (printdiff) { 1042163387Sdwmalone Printf("\n"); 1043163387Sdwmalone Printf("%*.*s%s\n", 1044163387Sdwmalone -(outip->ip_hl << 3), 1045163387Sdwmalone outip->ip_hl << 3, 1046163387Sdwmalone ip_hdr_key, 1047163387Sdwmalone proto->key); 1048163387Sdwmalone pkt_compare((void *)outip, packlen, 1049163387Sdwmalone (void *)hip, hiplen); 1050163387Sdwmalone } 1051100535Sfenner if (i == -2) { 1052100567Sdcs#ifndef ARCHAIC 1053100535Sfenner ip = (struct ip *)packet; 1054100535Sfenner if (ip->ip_ttl <= 1) 1055100535Sfenner Printf(" !"); 1056100535Sfenner#endif 1057100535Sfenner ++got_there; 1058100535Sfenner break; 1059100535Sfenner } 106018579Sfenner /* time exceeded in transit */ 106118579Sfenner if (i == -1) 106218579Sfenner break; 106318579Sfenner code = i - 1; 106418579Sfenner switch (code) { 106518579Sfenner 106618579Sfenner case ICMP_UNREACH_PORT: 106718579Sfenner#ifndef ARCHAIC 106818579Sfenner ip = (struct ip *)packet; 106918579Sfenner if (ip->ip_ttl <= 1) 107018579Sfenner Printf(" !"); 107118579Sfenner#endif 107218579Sfenner ++got_there; 107318579Sfenner break; 107418579Sfenner 107518579Sfenner case ICMP_UNREACH_NET: 107618579Sfenner ++unreachable; 107718579Sfenner Printf(" !N"); 107818579Sfenner break; 107918579Sfenner 108018579Sfenner case ICMP_UNREACH_HOST: 108118579Sfenner ++unreachable; 108218579Sfenner Printf(" !H"); 108318579Sfenner break; 108418579Sfenner 108518579Sfenner case ICMP_UNREACH_PROTOCOL: 108618579Sfenner ++got_there; 108718579Sfenner Printf(" !P"); 108818579Sfenner break; 108918579Sfenner 109018579Sfenner case ICMP_UNREACH_NEEDFRAG: 109118579Sfenner ++unreachable; 1092100787Sfenner Printf(" !F-%d", pmtu); 109318579Sfenner break; 109418579Sfenner 109518579Sfenner case ICMP_UNREACH_SRCFAIL: 109618579Sfenner ++unreachable; 109718579Sfenner Printf(" !S"); 109818579Sfenner break; 109918579Sfenner 1100159576Sdwmalone case ICMP_UNREACH_NET_UNKNOWN: 1101159576Sdwmalone ++unreachable; 1102159576Sdwmalone Printf(" !U"); 1103159576Sdwmalone break; 1104159576Sdwmalone 1105159576Sdwmalone case ICMP_UNREACH_HOST_UNKNOWN: 1106159576Sdwmalone ++unreachable; 1107159576Sdwmalone Printf(" !W"); 1108159576Sdwmalone break; 1109159576Sdwmalone 1110159576Sdwmalone case ICMP_UNREACH_ISOLATED: 1111159576Sdwmalone ++unreachable; 1112159576Sdwmalone Printf(" !I"); 1113159576Sdwmalone break; 1114159576Sdwmalone 1115159576Sdwmalone case ICMP_UNREACH_NET_PROHIB: 1116159576Sdwmalone ++unreachable; 1117159576Sdwmalone Printf(" !A"); 1118159576Sdwmalone break; 1119159576Sdwmalone 1120159576Sdwmalone case ICMP_UNREACH_HOST_PROHIB: 1121159576Sdwmalone ++unreachable; 1122159576Sdwmalone Printf(" !Z"); 1123159576Sdwmalone break; 1124159576Sdwmalone 1125159576Sdwmalone case ICMP_UNREACH_TOSNET: 1126159576Sdwmalone ++unreachable; 1127159576Sdwmalone Printf(" !Q"); 1128159576Sdwmalone break; 1129159576Sdwmalone 1130159576Sdwmalone case ICMP_UNREACH_TOSHOST: 1131159576Sdwmalone ++unreachable; 1132159576Sdwmalone Printf(" !T"); 1133159576Sdwmalone break; 1134159576Sdwmalone 113518579Sfenner case ICMP_UNREACH_FILTER_PROHIB: 113618579Sfenner ++unreachable; 113718579Sfenner Printf(" !X"); 113818579Sfenner break; 113918579Sfenner 1140100787Sfenner case ICMP_UNREACH_HOST_PRECEDENCE: 1141100787Sfenner ++unreachable; 1142100787Sfenner Printf(" !V"); 1143100787Sfenner break; 1144100787Sfenner 1145100787Sfenner case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1146100787Sfenner ++unreachable; 1147100787Sfenner Printf(" !C"); 1148100787Sfenner break; 1149100787Sfenner 115018579Sfenner default: 115118579Sfenner ++unreachable; 115218579Sfenner Printf(" !<%d>", code); 115318579Sfenner break; 115418579Sfenner } 115518579Sfenner break; 115618579Sfenner } 115718695Ssef if (cc == 0) { 115818695Ssef loss++; 115918579Sfenner Printf(" *"); 116018695Ssef } 116118579Sfenner (void)fflush(stdout); 116218579Sfenner } 116318803Ssef if (sump) { 116418811Ssef Printf(" (%d%% loss)", (loss * 100) / nprobes); 116518803Ssef } 116618579Sfenner putchar('\n'); 116718579Sfenner if (got_there || 116818579Sfenner (unreachable > 0 && unreachable >= nprobes - 1)) 116918579Sfenner break; 117018579Sfenner } 1171176428Srpaulo if (as_path) 1172176428Srpaulo as_shutdown(asn); 117318579Sfenner exit(0); 117418579Sfenner} 117518579Sfenner 117618579Sfennerint 117718579Sfennerwait_for_reply(register int sock, register struct sockaddr_in *fromp, 1178100787Sfenner register const struct timeval *tp) 117918579Sfenner{ 118066810Skris fd_set *fdsp; 118166810Skris size_t nfds; 118218579Sfenner struct timeval now, wait; 118318579Sfenner register int cc = 0; 118444086Sdes register int error; 118518579Sfenner int fromlen = sizeof(*fromp); 118618579Sfenner 118766810Skris nfds = howmany(sock + 1, NFDBITS); 118898709Srobert if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL) 118966810Skris err(1, "malloc"); 119098709Srobert memset(fdsp, 0, nfds * sizeof(fd_mask)); 119166810Skris FD_SET(sock, fdsp); 119218579Sfenner 119318579Sfenner wait.tv_sec = tp->tv_sec + waittime; 119418579Sfenner wait.tv_usec = tp->tv_usec; 1195211062Sed (void)gettimeofday(&now, NULL); 119618579Sfenner tvsub(&wait, &now); 119744086Sdes if (wait.tv_sec < 0) { 119844086Sdes wait.tv_sec = 0; 119944086Sdes wait.tv_usec = 1; 120044086Sdes } 120118579Sfenner 120266810Skris error = select(sock + 1, fdsp, NULL, NULL, &wait); 120344086Sdes if (error == -1 && errno == EINVAL) { 120444086Sdes Fprintf(stderr, "%s: botched select() args\n", prog); 120544086Sdes exit(1); 120644086Sdes } 120744086Sdes if (error > 0) 1208100787Sfenner cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, 120918579Sfenner (struct sockaddr *)fromp, &fromlen); 121018579Sfenner 121166810Skris free(fdsp); 121218579Sfenner return(cc); 121318579Sfenner} 121418579Sfenner 1215100787Sfennervoid 1216100787Sfennersend_probe(int seq, int ttl) 1217100787Sfenner{ 1218100787Sfenner register int cc; 1219100787Sfenner 1220100787Sfenner outip->ip_ttl = ttl; 1221100787Sfenner outip->ip_id = htons(ident + seq); 1222100787Sfenner 1223100787Sfenner /* XXX undocumented debugging hack */ 1224100787Sfenner if (verbose > 1) { 1225100787Sfenner register const u_short *sp; 1226100787Sfenner register int nshorts, i; 1227100787Sfenner 1228100787Sfenner sp = (u_short *)outip; 1229100787Sfenner nshorts = (u_int)packlen / sizeof(u_short); 1230100787Sfenner i = 0; 1231100787Sfenner Printf("[ %d bytes", packlen); 1232100787Sfenner while (--nshorts >= 0) { 1233100787Sfenner if ((i++ % 8) == 0) 1234100787Sfenner Printf("\n\t"); 1235100787Sfenner Printf(" %04x", ntohs(*sp++)); 1236100787Sfenner } 1237100787Sfenner if (packlen & 1) { 1238100787Sfenner if ((i % 8) == 0) 1239100787Sfenner Printf("\n\t"); 1240100787Sfenner Printf(" %02x", *(u_char *)sp); 1241100787Sfenner } 1242100787Sfenner Printf("]\n"); 1243100787Sfenner } 1244100787Sfenner 1245100787Sfenner#if !defined(IP_HDRINCL) && defined(IP_TTL) 1246100787Sfenner if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, 1247100787Sfenner (char *)&ttl, sizeof(ttl)) < 0) { 1248100787Sfenner Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", 1249100787Sfenner prog, ttl, strerror(errno)); 1250100787Sfenner exit(1); 1251100787Sfenner } 1252100787Sfenner#endif 1253100787Sfenner 1254100787Sfenner cc = sendto(sndsock, (char *)outip, 1255100787Sfenner packlen, 0, &whereto, sizeof(whereto)); 1256100787Sfenner if (cc < 0 || cc != packlen) { 1257100787Sfenner if (cc < 0) 1258100787Sfenner Fprintf(stderr, "%s: sendto: %s\n", 1259100787Sfenner prog, strerror(errno)); 1260100787Sfenner Printf("%s: wrote %s %d chars, ret=%d\n", 1261100787Sfenner prog, hostname, packlen, cc); 1262100787Sfenner (void)fflush(stdout); 1263100787Sfenner } 1264100787Sfenner} 1265100787Sfenner 126658804Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 126758804Sshinint 126858804Sshinsetpolicy(so, policy) 126958804Sshin int so; 127058804Sshin char *policy; 127158804Sshin{ 127258804Sshin char *buf; 127358804Sshin 127458804Sshin buf = ipsec_set_policy(policy, strlen(policy)); 127558804Sshin if (buf == NULL) { 127666809Skris warnx("%s", ipsec_strerror()); 127758804Sshin return -1; 127858804Sshin } 127958804Sshin (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY, 128058804Sshin buf, ipsec_get_policylen(buf)); 128158804Sshin 128258804Sshin free(buf); 128358804Sshin 128458804Sshin return 0; 128558804Sshin} 128658804Sshin#endif 128758804Sshin 128818579Sfennerdouble 128918579SfennerdeltaT(struct timeval *t1p, struct timeval *t2p) 129018579Sfenner{ 129118579Sfenner register double dt; 129218579Sfenner 129318579Sfenner dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 129418579Sfenner (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 129518579Sfenner return (dt); 129618579Sfenner} 129718579Sfenner 129818579Sfenner/* 129918579Sfenner * Convert an ICMP "type" field to a printable string. 130018579Sfenner */ 130118579Sfennerchar * 130218579Sfennerpr_type(register u_char t) 130318579Sfenner{ 130418579Sfenner static char *ttab[] = { 130518579Sfenner "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 130618579Sfenner "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 130718579Sfenner "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 130818579Sfenner "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 130918579Sfenner "Info Reply" 131018579Sfenner }; 131118579Sfenner 131218579Sfenner if (t > 16) 131318579Sfenner return("OUT-OF-RANGE"); 131418579Sfenner 131518579Sfenner return(ttab[t]); 131618579Sfenner} 131718579Sfenner 131818579Sfennerint 131918579Sfennerpacket_ok(register u_char *buf, int cc, register struct sockaddr_in *from, 132018579Sfenner register int seq) 132118579Sfenner{ 132218579Sfenner register struct icmp *icp; 132318579Sfenner register u_char type, code; 132418579Sfenner register int hlen; 132518579Sfenner#ifndef ARCHAIC 132618579Sfenner register struct ip *ip; 132718579Sfenner 132818579Sfenner ip = (struct ip *) buf; 132918579Sfenner hlen = ip->ip_hl << 2; 133018579Sfenner if (cc < hlen + ICMP_MINLEN) { 133118579Sfenner if (verbose) 133218579Sfenner Printf("packet too short (%d bytes) from %s\n", cc, 133318579Sfenner inet_ntoa(from->sin_addr)); 133418579Sfenner return (0); 133518579Sfenner } 133618579Sfenner cc -= hlen; 133718579Sfenner icp = (struct icmp *)(buf + hlen); 133818579Sfenner#else 133918579Sfenner icp = (struct icmp *)buf; 134018579Sfenner#endif 134118579Sfenner type = icp->icmp_type; 134218579Sfenner code = icp->icmp_code; 1343100787Sfenner /* Path MTU Discovery (RFC1191) */ 1344100787Sfenner if (code != ICMP_UNREACH_NEEDFRAG) 1345100787Sfenner pmtu = 0; 1346100787Sfenner else { 1347100787Sfenner#ifdef HAVE_ICMP_NEXTMTU 1348100787Sfenner pmtu = ntohs(icp->icmp_nextmtu); 1349100787Sfenner#else 1350100787Sfenner pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu); 1351100787Sfenner#endif 1352100787Sfenner } 1353100535Sfenner if (type == ICMP_ECHOREPLY 1354100535Sfenner && proto->num == IPPROTO_ICMP 1355124859Scperciva && (*proto->check)((u_char *)icp, (u_char)seq)) 1356100535Sfenner return -2; 135718579Sfenner if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 135818579Sfenner type == ICMP_UNREACH) { 135946542Sarchie u_char *inner; 136018579Sfenner 136118579Sfenner hip = &icp->icmp_ip; 1362163387Sdwmalone hiplen = ((u_char *)icp + cc) - (u_char *)hip; 136318579Sfenner hlen = hip->ip_hl << 2; 136446542Sarchie inner = (u_char *)((u_char *)hip + hlen); 1365283958Stuexen if (hlen + 16 <= cc 136646542Sarchie && hip->ip_p == proto->num 1367124859Scperciva && (*proto->check)(inner, (u_char)seq)) 136818579Sfenner return (type == ICMP_TIMXCEED ? -1 : code + 1); 136918579Sfenner } 137018579Sfenner#ifndef ARCHAIC 137118579Sfenner if (verbose) { 137218579Sfenner register int i; 137318579Sfenner u_int32_t *lp = (u_int32_t *)&icp->icmp_ip; 137418579Sfenner 137518579Sfenner Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr)); 137618579Sfenner Printf("%s: icmp type %d (%s) code %d\n", 137718579Sfenner inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); 1378283958Stuexen for (i = 4; i <= cc - ICMP_MINLEN; i += sizeof(*lp)) 1379283958Stuexen Printf("%2d: %8.8x\n", i, ntohl(*lp++)); 138018579Sfenner } 138118579Sfenner#endif 138218579Sfenner return(0); 138318579Sfenner} 138418579Sfenner 138546542Sarchievoid 1386100535Sfennericmp_prep(struct outdata *outdata) 1387100535Sfenner{ 1388100787Sfenner struct icmp *const icmpheader = (struct icmp *) outp; 1389100535Sfenner 1390100535Sfenner icmpheader->icmp_type = ICMP_ECHO; 1391100535Sfenner icmpheader->icmp_id = htons(ident); 1392100535Sfenner icmpheader->icmp_seq = htons(outdata->seq); 1393100535Sfenner icmpheader->icmp_cksum = 0; 1394100789Sfenner icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen); 1395100535Sfenner if (icmpheader->icmp_cksum == 0) 1396100535Sfenner icmpheader->icmp_cksum = 0xffff; 1397100535Sfenner} 1398100535Sfenner 1399100535Sfennerint 1400100535Sfennericmp_check(const u_char *data, int seq) 1401100535Sfenner{ 1402100535Sfenner struct icmp *const icmpheader = (struct icmp *) data; 1403100535Sfenner 1404100535Sfenner return (icmpheader->icmp_id == htons(ident) 1405100535Sfenner && icmpheader->icmp_seq == htons(seq)); 1406100535Sfenner} 1407100535Sfenner 1408100535Sfennervoid 140946542Sarchieudp_prep(struct outdata *outdata) 141046542Sarchie{ 1411100787Sfenner struct udphdr *const outudp = (struct udphdr *) outp; 141218579Sfenner 1413158424Scjc outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0)); 1414158424Scjc outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1415100787Sfenner outudp->uh_ulen = htons((u_short)protlen); 1416100789Sfenner outudp->uh_sum = 0; 1417100787Sfenner if (doipcksum) { 1418283958Stuexen u_short sum = p_cksum(outip, (u_short*)outudp, protlen, protlen); 1419100789Sfenner outudp->uh_sum = (sum) ? sum : 0xffff; 1420100787Sfenner } 1421100789Sfenner 1422100789Sfenner return; 142346542Sarchie} 142446542Sarchie 142546542Sarchieint 142646542Sarchieudp_check(const u_char *data, int seq) 142746542Sarchie{ 142846542Sarchie struct udphdr *const udp = (struct udphdr *) data; 142946542Sarchie 1430158424Scjc return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) && 1431158424Scjc ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq)); 143246542Sarchie} 143346542Sarchie 143418579Sfennervoid 1435283958Stuexenudplite_prep(struct outdata *outdata) 1436283958Stuexen{ 1437283958Stuexen struct udphdr *const outudp = (struct udphdr *) outp; 1438283958Stuexen 1439283958Stuexen outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0)); 1440283958Stuexen outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1441283958Stuexen outudp->uh_ulen = htons(8); 1442283958Stuexen outudp->uh_sum = 0; 1443283958Stuexen if (doipcksum) { 1444283958Stuexen u_short sum = p_cksum(outip, (u_short*)outudp, protlen, 8); 1445283958Stuexen outudp->uh_sum = (sum) ? sum : 0xffff; 1446283958Stuexen } 1447283958Stuexen 1448283958Stuexen return; 1449283958Stuexen} 1450283958Stuexen 1451283958Stuexenint 1452283958Stuexenudplite_check(const u_char *data, int seq) 1453283958Stuexen{ 1454283958Stuexen struct udphdr *const udp = (struct udphdr *) data; 1455283958Stuexen 1456283958Stuexen return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) && 1457283958Stuexen ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq)); 1458283958Stuexen} 1459283958Stuexen 1460283958Stuexenvoid 146146542Sarchietcp_prep(struct outdata *outdata) 146246542Sarchie{ 1463100787Sfenner struct tcphdr *const tcp = (struct tcphdr *) outp; 146446542Sarchie 146546542Sarchie tcp->th_sport = htons(ident); 1466158424Scjc tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq)); 1467234701Stuexen tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport; 146846542Sarchie tcp->th_ack = 0; 146946542Sarchie tcp->th_off = 5; 147046542Sarchie tcp->th_flags = TH_SYN; 1471100789Sfenner tcp->th_sum = 0; 1472100789Sfenner 1473283958Stuexen if (doipcksum) 1474283958Stuexen tcp->th_sum = p_cksum(outip, (u_short*)tcp, protlen, protlen); 147546542Sarchie} 147646542Sarchie 147746542Sarchieint 147846542Sarchietcp_check(const u_char *data, int seq) 147946542Sarchie{ 148046542Sarchie struct tcphdr *const tcp = (struct tcphdr *) data; 148146542Sarchie 148246542Sarchie return (ntohs(tcp->th_sport) == ident 1483234701Stuexen && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq) 1484234701Stuexen && tcp->th_seq == (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport)); 148546542Sarchie} 148646542Sarchie 148746542Sarchievoid 1488283958Stuexensctp_prep(struct outdata *outdata) 1489283958Stuexen{ 1490283958Stuexen struct sctphdr *const sctp = (struct sctphdr *) outp; 1491283958Stuexen struct sctp_chunkhdr *chk; 1492283958Stuexen 1493283958Stuexen sctp->src_port = htons(ident); 1494283958Stuexen sctp->dest_port = htons(port + (fixedPort ? 0 : outdata->seq)); 1495283958Stuexen sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port; 1496283958Stuexen sctp->checksum = htonl(0); 1497283958Stuexen if (protlen >= 1498283958Stuexen (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) { 1499283958Stuexen chk = (struct sctp_chunkhdr *)(sctp + 1); 1500283958Stuexen chk->chunk_type = SCTP_SHUTDOWN_ACK; 1501283958Stuexen chk->chunk_flags = 0; 1502283958Stuexen chk->chunk_length = htons(4); 1503283958Stuexen } 1504283958Stuexen if (protlen >= 1505283958Stuexen (int)(sizeof(struct sctphdr) + 2 * sizeof(struct sctp_chunkhdr))) { 1506283958Stuexen chk = chk + 1; 1507283958Stuexen chk->chunk_type = SCTP_PAD_CHUNK; 1508283958Stuexen chk->chunk_flags = 0; 1509283958Stuexen chk->chunk_length = htons(protlen - 1510283958Stuexen (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))); 1511283958Stuexen } 1512283958Stuexen if (doipcksum) { 1513283958Stuexen sctp->checksum = sctp_crc32c(sctp, protlen); 1514283958Stuexen } 1515283958Stuexen} 1516283958Stuexen 1517283958Stuexenint 1518283958Stuexensctp_check(const u_char *data, int seq) 1519283958Stuexen{ 1520283958Stuexen struct sctphdr *const sctp = (struct sctphdr *) data; 1521283958Stuexen 1522283958Stuexen return (ntohs(sctp->src_port) == ident 1523283958Stuexen && ntohs(sctp->dest_port) == port + (fixedPort ? 0 : seq) 1524283958Stuexen && sctp->v_tag == 1525283958Stuexen (u_int32_t)((sctp->src_port << 16) | sctp->dest_port)); 1526283958Stuexen} 1527283958Stuexen 1528283958Stuexenvoid 152946542Sarchiegre_prep(struct outdata *outdata) 153046542Sarchie{ 1531100787Sfenner struct grehdr *const gre = (struct grehdr *) outp; 153246542Sarchie 153346542Sarchie gre->flags = htons(0x2001); 153446542Sarchie gre->proto = htons(port); 153546542Sarchie gre->length = 0; 153646542Sarchie gre->callId = htons(ident + outdata->seq); 153746542Sarchie} 153846542Sarchie 153946542Sarchieint 154046542Sarchiegre_check(const u_char *data, int seq) 154146542Sarchie{ 154246542Sarchie struct grehdr *const gre = (struct grehdr *) data; 154346542Sarchie 154446542Sarchie return(ntohs(gre->proto) == port 154546542Sarchie && ntohs(gre->callId) == ident + seq); 154646542Sarchie} 154746542Sarchie 154846542Sarchievoid 154946542Sarchiegen_prep(struct outdata *outdata) 155046542Sarchie{ 1551100787Sfenner u_int16_t *const ptr = (u_int16_t *) outp; 155246542Sarchie 155346542Sarchie ptr[0] = htons(ident); 155446542Sarchie ptr[1] = htons(port + outdata->seq); 155546542Sarchie} 155646542Sarchie 155746542Sarchieint 155846542Sarchiegen_check(const u_char *data, int seq) 155946542Sarchie{ 156046542Sarchie u_int16_t *const ptr = (u_int16_t *) data; 156146542Sarchie 156246542Sarchie return(ntohs(ptr[0]) == ident 156346542Sarchie && ntohs(ptr[1]) == port + seq); 156446542Sarchie} 156546542Sarchie 156646542Sarchievoid 156718579Sfennerprint(register u_char *buf, register int cc, register struct sockaddr_in *from) 156818579Sfenner{ 156918579Sfenner register struct ip *ip; 157018579Sfenner register int hlen; 1571196475Sume char addr[INET_ADDRSTRLEN]; 157218579Sfenner 157318579Sfenner ip = (struct ip *) buf; 157418579Sfenner hlen = ip->ip_hl << 2; 157518579Sfenner cc -= hlen; 157618579Sfenner 1577196475Sume strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr)); 1578196475Sume 1579176428Srpaulo if (as_path) 1580196475Sume Printf(" [AS%u]", as_lookup(asn, addr, AF_INET)); 1581176428Srpaulo 158218579Sfenner if (nflag) 1583196475Sume Printf(" %s", addr); 158418579Sfenner else 1585196475Sume Printf(" %s (%s)", inetname(from->sin_addr), addr); 158618579Sfenner 158718579Sfenner if (verbose) 158818579Sfenner Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 158918579Sfenner} 159018579Sfenner 159118579Sfenner/* 1592100789Sfenner * Checksum routine for UDP and TCP headers. 1593100789Sfenner */ 1594283958Stuexenu_short 1595283958Stuexenp_cksum(struct ip *ip, u_short *data, int len, int cov) 1596100789Sfenner{ 1597100789Sfenner static struct ipovly ipo; 1598216184Suqs u_short sum[2]; 1599100789Sfenner 1600100789Sfenner ipo.ih_pr = ip->ip_p; 1601100789Sfenner ipo.ih_len = htons(len); 1602100789Sfenner ipo.ih_src = ip->ip_src; 1603100789Sfenner ipo.ih_dst = ip->ip_dst; 1604100789Sfenner 1605216184Suqs sum[1] = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */ 1606283958Stuexen sum[0] = in_cksum(data, cov); /* payload data cksum */ 1607100789Sfenner 1608216184Suqs return ~in_cksum(sum, sizeof(sum)); 1609100789Sfenner} 1610100789Sfenner 1611100789Sfenner/* 161218579Sfenner * Checksum routine for Internet Protocol family headers (C Version) 161318579Sfenner */ 1614100535Sfenneru_short 161518579Sfennerin_cksum(register u_short *addr, register int len) 161618579Sfenner{ 161718579Sfenner register int nleft = len; 161818579Sfenner register u_short *w = addr; 161918579Sfenner register u_short answer; 162018579Sfenner register int sum = 0; 162118579Sfenner 162218579Sfenner /* 162318579Sfenner * Our algorithm is simple, using a 32 bit accumulator (sum), 162418579Sfenner * we add sequential 16 bit words to it, and at the end, fold 162518579Sfenner * back all the carry bits from the top 16 bits into the lower 162618579Sfenner * 16 bits. 162718579Sfenner */ 162818579Sfenner while (nleft > 1) { 162918579Sfenner sum += *w++; 163018579Sfenner nleft -= 2; 163118579Sfenner } 163218579Sfenner 163318579Sfenner /* mop up an odd byte, if necessary */ 163418579Sfenner if (nleft == 1) 163518579Sfenner sum += *(u_char *)w; 163618579Sfenner 163718579Sfenner /* 163818579Sfenner * add back carry outs from top 16 bits to low 16 bits 163918579Sfenner */ 164018579Sfenner sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 164118579Sfenner sum += (sum >> 16); /* add carry */ 164218579Sfenner answer = ~sum; /* truncate to 16 bits */ 164318579Sfenner return (answer); 164418579Sfenner} 164518579Sfenner 164618579Sfenner/* 1647283958Stuexen * CRC32C routine for the Stream Control Transmission Protocol 1648283958Stuexen */ 1649283958Stuexen 1650283958Stuexen#define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF]) 1651283958Stuexen 1652283958Stuexenstatic u_int32_t crc_c[256] = { 1653283958Stuexen 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 1654283958Stuexen 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 1655283958Stuexen 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 1656283958Stuexen 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 1657283958Stuexen 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 1658283958Stuexen 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 1659283958Stuexen 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 1660283958Stuexen 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 1661283958Stuexen 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 1662283958Stuexen 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 1663283958Stuexen 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 1664283958Stuexen 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 1665283958Stuexen 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 1666283958Stuexen 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 1667283958Stuexen 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 1668283958Stuexen 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 1669283958Stuexen 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 1670283958Stuexen 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 1671283958Stuexen 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 1672283958Stuexen 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 1673283958Stuexen 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 1674283958Stuexen 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 1675283958Stuexen 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 1676283958Stuexen 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 1677283958Stuexen 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 1678283958Stuexen 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 1679283958Stuexen 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 1680283958Stuexen 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 1681283958Stuexen 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 1682283958Stuexen 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 1683283958Stuexen 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 1684283958Stuexen 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 1685283958Stuexen 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 1686283958Stuexen 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 1687283958Stuexen 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 1688283958Stuexen 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 1689283958Stuexen 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 1690283958Stuexen 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 1691283958Stuexen 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 1692283958Stuexen 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 1693283958Stuexen 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 1694283958Stuexen 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 1695283958Stuexen 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 1696283958Stuexen 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 1697283958Stuexen 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 1698283958Stuexen 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 1699283958Stuexen 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 1700283958Stuexen 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 1701283958Stuexen 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 1702283958Stuexen 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 1703283958Stuexen 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 1704283958Stuexen 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 1705283958Stuexen 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 1706283958Stuexen 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 1707283958Stuexen 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 1708283958Stuexen 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 1709283958Stuexen 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 1710283958Stuexen 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 1711283958Stuexen 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 1712283958Stuexen 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 1713283958Stuexen 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 1714283958Stuexen 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 1715283958Stuexen 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 1716283958Stuexen 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 1717283958Stuexen}; 1718283958Stuexen 1719283958Stuexenu_int32_t 1720283958Stuexensctp_crc32c(const void *packet, u_int32_t len) 1721283958Stuexen{ 1722283958Stuexen u_int32_t i, crc32c; 1723283958Stuexen u_int8_t byte0, byte1, byte2, byte3; 1724283958Stuexen const u_int8_t *buf = (const u_int8_t *)packet; 1725283958Stuexen 1726283958Stuexen crc32c = ~0; 1727283958Stuexen for (i = 0; i < len; i++) 1728283958Stuexen CRC32C(crc32c, buf[i]); 1729283958Stuexen crc32c = ~crc32c; 1730283958Stuexen byte0 = crc32c & 0xff; 1731283958Stuexen byte1 = (crc32c>>8) & 0xff; 1732283958Stuexen byte2 = (crc32c>>16) & 0xff; 1733283958Stuexen byte3 = (crc32c>>24) & 0xff; 1734283958Stuexen crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 1735283958Stuexen return htonl(crc32c); 1736283958Stuexen} 1737283958Stuexen 1738283958Stuexen/* 173918579Sfenner * Subtract 2 timeval structs: out = out - in. 174044086Sdes * Out is assumed to be within about LONG_MAX seconds of in. 174118579Sfenner */ 174218579Sfennervoid 174318579Sfennertvsub(register struct timeval *out, register struct timeval *in) 174418579Sfenner{ 174518579Sfenner 174618579Sfenner if ((out->tv_usec -= in->tv_usec) < 0) { 174718579Sfenner --out->tv_sec; 174818579Sfenner out->tv_usec += 1000000; 174918579Sfenner } 175018579Sfenner out->tv_sec -= in->tv_sec; 175118579Sfenner} 175218579Sfenner 175318579Sfenner/* 175418579Sfenner * Construct an Internet address representation. 175518579Sfenner * If the nflag has been supplied, give 175618579Sfenner * numeric value, otherwise try for symbolic name. 175718579Sfenner */ 175818579Sfennerchar * 175918579Sfennerinetname(struct in_addr in) 176018579Sfenner{ 176118579Sfenner register char *cp; 176218579Sfenner register struct hostent *hp; 176318579Sfenner static int first = 1; 176418579Sfenner static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1]; 176518579Sfenner 176618579Sfenner if (first && !nflag) { 176718579Sfenner first = 0; 1768100787Sfenner if (gethostname(domain, sizeof(domain) - 1) < 0) 176918579Sfenner domain[0] = '\0'; 1770100787Sfenner else { 1771100787Sfenner cp = strchr(domain, '.'); 1772100787Sfenner if (cp == NULL) { 1773100787Sfenner hp = gethostbyname(domain); 1774100787Sfenner if (hp != NULL) 1775100787Sfenner cp = strchr(hp->h_name, '.'); 1776100787Sfenner } 1777100787Sfenner if (cp == NULL) 1778100787Sfenner domain[0] = '\0'; 1779100787Sfenner else { 1780100787Sfenner ++cp; 1781100787Sfenner (void)strncpy(domain, cp, sizeof(domain) - 1); 1782100787Sfenner domain[sizeof(domain) - 1] = '\0'; 1783100787Sfenner } 1784100787Sfenner } 178518579Sfenner } 178618579Sfenner if (!nflag && in.s_addr != INADDR_ANY) { 178718579Sfenner hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); 178818579Sfenner if (hp != NULL) { 178918579Sfenner if ((cp = strchr(hp->h_name, '.')) != NULL && 179018579Sfenner strcmp(cp + 1, domain) == 0) 179118579Sfenner *cp = '\0'; 179218579Sfenner (void)strncpy(line, hp->h_name, sizeof(line) - 1); 179318579Sfenner line[sizeof(line) - 1] = '\0'; 179418579Sfenner return (line); 179518579Sfenner } 179618579Sfenner } 179718579Sfenner return (inet_ntoa(in)); 179818579Sfenner} 179918579Sfenner 1800100787Sfennerstruct hostinfo * 1801100787Sfennergethostinfo(register char *hostname) 180218579Sfenner{ 1803100787Sfenner register int n; 180418579Sfenner register struct hostent *hp; 1805100787Sfenner register struct hostinfo *hi; 1806100787Sfenner register char **p; 1807100787Sfenner register u_int32_t addr, *ap; 180818579Sfenner 1809223579Sdim if (strlen(hostname) >= MAXHOSTNAMELEN) { 1810100787Sfenner Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", 1811100787Sfenner prog, hostname); 1812100787Sfenner exit(1); 1813100787Sfenner } 1814100787Sfenner hi = calloc(1, sizeof(*hi)); 1815100787Sfenner if (hi == NULL) { 1816100787Sfenner Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1817100787Sfenner exit(1); 1818100787Sfenner } 1819100787Sfenner addr = inet_addr(hostname); 1820100787Sfenner if ((int32_t)addr != -1) { 1821100787Sfenner hi->name = strdup(hostname); 1822100787Sfenner hi->n = 1; 1823100787Sfenner hi->addrs = calloc(1, sizeof(hi->addrs[0])); 1824100787Sfenner if (hi->addrs == NULL) { 1825100787Sfenner Fprintf(stderr, "%s: calloc %s\n", 1826100787Sfenner prog, strerror(errno)); 1827100787Sfenner exit(1); 1828100787Sfenner } 1829100787Sfenner hi->addrs[0] = addr; 1830100787Sfenner return (hi); 1831100787Sfenner } 183218579Sfenner 183318579Sfenner hp = gethostbyname(hostname); 183418579Sfenner if (hp == NULL) { 183518579Sfenner Fprintf(stderr, "%s: unknown host %s\n", prog, hostname); 183618579Sfenner exit(1); 183718579Sfenner } 183818579Sfenner if (hp->h_addrtype != AF_INET || hp->h_length != 4) { 183918579Sfenner Fprintf(stderr, "%s: bad host %s\n", prog, hostname); 184018579Sfenner exit(1); 184118579Sfenner } 1842100787Sfenner hi->name = strdup(hp->h_name); 1843100787Sfenner for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) 1844100787Sfenner continue; 1845100787Sfenner hi->n = n; 1846100787Sfenner hi->addrs = calloc(n, sizeof(hi->addrs[0])); 1847100787Sfenner if (hi->addrs == NULL) { 1848100787Sfenner Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); 1849100787Sfenner exit(1); 1850100787Sfenner } 1851100787Sfenner for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) 1852100787Sfenner memcpy(ap, *p, sizeof(*ap)); 1853100787Sfenner return (hi); 185418579Sfenner} 185518579Sfenner 1856100787Sfennervoid 1857100787Sfennerfreehostinfo(register struct hostinfo *hi) 185818579Sfenner{ 1859100787Sfenner if (hi->name != NULL) { 1860100787Sfenner free(hi->name); 1861100787Sfenner hi->name = NULL; 1862100787Sfenner } 1863100787Sfenner free((char *)hi->addrs); 1864100787Sfenner free((char *)hi); 1865100787Sfenner} 186618579Sfenner 1867100787Sfennervoid 1868100787Sfennergetaddr(register u_int32_t *ap, register char *hostname) 1869100787Sfenner{ 1870100787Sfenner register struct hostinfo *hi; 1871100787Sfenner 1872100787Sfenner hi = gethostinfo(hostname); 1873100787Sfenner *ap = hi->addrs[0]; 1874100787Sfenner freehostinfo(hi); 1875100787Sfenner} 1876100787Sfenner 1877100787Sfennervoid 1878100787Sfennersetsin(register struct sockaddr_in *sin, register u_int32_t addr) 1879100787Sfenner{ 1880100787Sfenner 188118579Sfenner memset(sin, 0, sizeof(*sin)); 1882100787Sfenner#ifdef HAVE_SOCKADDR_SA_LEN 1883100787Sfenner sin->sin_len = sizeof(*sin); 1884100787Sfenner#endif 188518579Sfenner sin->sin_family = AF_INET; 1886100787Sfenner sin->sin_addr.s_addr = addr; 188718579Sfenner} 188818579Sfenner 1889100787Sfenner/* String to value with optional min and max. Handles decimal and hex. */ 1890100787Sfennerint 1891100787Sfennerstr2val(register const char *str, register const char *what, 1892100787Sfenner register int mi, register int ma) 189318579Sfenner{ 1894100787Sfenner register const char *cp; 1895100787Sfenner register int val; 1896100787Sfenner char *ep; 189718579Sfenner 1898100787Sfenner if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 1899100787Sfenner cp = str + 2; 1900100787Sfenner val = (int)strtol(cp, &ep, 16); 1901100787Sfenner } else 1902100787Sfenner val = (int)strtol(str, &ep, 10); 1903100787Sfenner if (*ep != '\0') { 1904100787Sfenner Fprintf(stderr, "%s: \"%s\" bad value for %s \n", 1905100787Sfenner prog, str, what); 190618579Sfenner exit(1); 190718579Sfenner } 1908100787Sfenner if (val < mi && mi >= 0) { 1909100787Sfenner if (mi == 0) 1910100787Sfenner Fprintf(stderr, "%s: %s must be >= %d\n", 1911100787Sfenner prog, what, mi); 1912100787Sfenner else 1913100787Sfenner Fprintf(stderr, "%s: %s must be > %d\n", 1914100787Sfenner prog, what, mi - 1); 1915100787Sfenner exit(1); 1916100787Sfenner } 1917100787Sfenner if (val > ma && ma >= 0) { 1918100787Sfenner Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); 1919100787Sfenner exit(1); 1920100787Sfenner } 1921100787Sfenner return (val); 192218579Sfenner} 192318579Sfenner 1924100787Sfennerstruct outproto * 1925100787Sfennersetproto(char *pname) 1926100787Sfenner{ 1927100787Sfenner struct outproto *proto; 1928100787Sfenner int i; 1929100787Sfenner 1930100787Sfenner for (i = 0; protos[i].name != NULL; i++) { 1931100787Sfenner if (strcasecmp(protos[i].name, pname) == 0) { 1932100787Sfenner break; 1933100787Sfenner } 1934100787Sfenner } 1935100787Sfenner proto = &protos[i]; 1936100787Sfenner if (proto->name == NULL) { /* generic handler */ 1937100787Sfenner struct protoent *pe; 1938100787Sfenner u_long pnum; 1939100787Sfenner 1940100787Sfenner /* Determine the IP protocol number */ 1941100787Sfenner if ((pe = getprotobyname(pname)) != NULL) 1942100787Sfenner pnum = pe->p_proto; 1943100787Sfenner else 1944100787Sfenner pnum = str2val(optarg, "proto number", 1, 255); 1945100787Sfenner proto->num = pnum; 1946100787Sfenner } 1947100787Sfenner return proto; 1948100787Sfenner} 1949100787Sfenner 195067682Sobrienvoid 1951163387Sdwmalonepkt_compare(const u_char *a, int la, const u_char *b, int lb) { 1952163387Sdwmalone int l; 1953163387Sdwmalone int i; 1954163387Sdwmalone 1955163387Sdwmalone for (i = 0; i < la; i++) 1956163387Sdwmalone Printf("%02x", (unsigned int)a[i]); 1957163387Sdwmalone Printf("\n"); 1958163387Sdwmalone l = (la <= lb) ? la : lb; 1959163387Sdwmalone for (i = 0; i < l; i++) 1960163387Sdwmalone if (a[i] == b[i]) 1961163387Sdwmalone Printf("__"); 1962163387Sdwmalone else 1963163387Sdwmalone Printf("%02x", (unsigned int)b[i]); 1964163387Sdwmalone for (; i < lb; i++) 1965163387Sdwmalone Printf("%02x", (unsigned int)b[i]); 1966163387Sdwmalone Printf("\n"); 1967163387Sdwmalone} 1968163387Sdwmalone 1969163387Sdwmalone 1970163387Sdwmalonevoid 197118579Sfennerusage(void) 197218579Sfenner{ 197318579Sfenner extern char version[]; 197418579Sfenner 197518579Sfenner Fprintf(stderr, "Version %s\n", version); 1976100787Sfenner Fprintf(stderr, 1977176428Srpaulo "Usage: %s [-adDeFInrSvx] [-f first_ttl] [-g gateway] [-i iface]\n" 1978100787Sfenner "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n" 1979176428Srpaulo "\t[-t tos] [-w waittime] [-A as_server] [-z pausemsecs] host [packetlen]\n", prog); 198018579Sfenner exit(1); 198118579Sfenner} 1982