1331722Seadler/* 21558Srgrimes * Copyright (c) 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Mike Muuss. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 33114589Sobrien#if 0 341558Srgrimes#ifndef lint 3523247Swollmanstatic const char copyright[] = 361558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 371558Srgrimes The Regents of the University of California. All rights reserved.\n"; 381558Srgrimes#endif /* not lint */ 391558Srgrimes 401558Srgrimes#ifndef lint 411558Srgrimesstatic char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; 42114589Sobrien#endif /* not lint */ 4337671Scharnier#endif 44114589Sobrien#include <sys/cdefs.h> 45114589Sobrien__FBSDID("$FreeBSD: stable/11/sbin/ping/ping.c 342143 2018-12-16 01:19:10Z eugen $"); 461558Srgrimes 471558Srgrimes/* 481558Srgrimes * P I N G . C 491558Srgrimes * 5037671Scharnier * Using the Internet Control Message Protocol (ICMP) "ECHO" facility, 511558Srgrimes * measure round-trip-delays and packet loss across network paths. 521558Srgrimes * 531558Srgrimes * Author - 541558Srgrimes * Mike Muuss 551558Srgrimes * U. S. Army Ballistic Research Laboratory 561558Srgrimes * December, 1983 571558Srgrimes * 581558Srgrimes * Status - 591558Srgrimes * Public Domain. Distribution Unlimited. 601558Srgrimes * Bugs - 611558Srgrimes * More statistics could always be gathered. 621558Srgrimes * This program has to run SUID to ROOT to access the ICMP socket. 631558Srgrimes */ 641558Srgrimes 6523247Swollman#include <sys/param.h> /* NB: we rely on this for <sys/types.h> */ 66263234Srwatson#include <sys/capsicum.h> 67109733Smaxim#include <sys/socket.h> 68109731Smaxim#include <sys/sysctl.h> 69109733Smaxim#include <sys/time.h> 70109733Smaxim#include <sys/uio.h> 7123247Swollman 72109733Smaxim#include <netinet/in.h> 73109733Smaxim#include <netinet/in_systm.h> 74109733Smaxim#include <netinet/ip.h> 75109733Smaxim#include <netinet/ip_icmp.h> 76109733Smaxim#include <netinet/ip_var.h> 77109733Smaxim#include <arpa/inet.h> 78296047Soshogbo 79296047Soshogbo#ifdef HAVE_LIBCASPER 80296047Soshogbo#include <libcasper.h> 81296047Soshogbo#include <casper/cap_dns.h> 82261498Spjd#endif 83109733Smaxim 84109733Smaxim#ifdef IPSEC 85171135Sgnn#include <netipsec/ipsec.h> 86109733Smaxim#endif /*IPSEC*/ 87109733Smaxim 8823247Swollman#include <ctype.h> 8923247Swollman#include <err.h> 9023247Swollman#include <errno.h> 9127508Swollman#include <math.h> 9223247Swollman#include <netdb.h> 9323247Swollman#include <signal.h> 9423247Swollman#include <stdio.h> 9523247Swollman#include <stdlib.h> 9623247Swollman#include <string.h> 9723247Swollman#include <sysexits.h> 9823247Swollman#include <unistd.h> 9923247Swollman 10099446Smaxim#define INADDR_LEN ((int)sizeof(in_addr_t)) 101135957Smaxim#define TIMEVAL_LEN ((int)sizeof(struct tv32)) 102111765Smdodd#define MASK_LEN (ICMP_MASKLEN - ICMP_MINLEN) 103111765Smdodd#define TS_LEN (ICMP_TSLEN - ICMP_MINLEN) 104112729Smdodd#define DEFDATALEN 56 /* default data length */ 10527533Sbde#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */ 10627533Sbde /* runs out of buffer space */ 10799447Smaxim#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN) 10899447Smaxim#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN) 109157535Sglebius#define MAXWAIT 10000 /* max ms to wait for response */ 11056342Sbillf#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ 111109731Smaxim#define MAXTOS 255 1121558Srgrimes 1131558Srgrimes#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 1141558Srgrimes#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 1151558Srgrimes#define SET(bit) (A(bit) |= B(bit)) 1161558Srgrimes#define CLR(bit) (A(bit) &= (~B(bit))) 1171558Srgrimes#define TST(bit) (A(bit) & B(bit)) 1181558Srgrimes 119135957Smaximstruct tv32 { 120135957Smaxim int32_t tv32_sec; 121135957Smaxim int32_t tv32_usec; 122135957Smaxim}; 123135957Smaxim 1241558Srgrimes/* various options */ 125273295Shrsstatic int options; 12620540Sfenner#define F_FLOOD 0x0001 12720540Sfenner#define F_INTERVAL 0x0002 12820540Sfenner#define F_NUMERIC 0x0004 12920540Sfenner#define F_PINGFILLED 0x0008 13020540Sfenner#define F_QUIET 0x0010 13120540Sfenner#define F_RROUTE 0x0020 13220540Sfenner#define F_SO_DEBUG 0x0040 13320540Sfenner#define F_SO_DONTROUTE 0x0080 13420540Sfenner#define F_VERBOSE 0x0100 13520540Sfenner#define F_QUIET2 0x0200 13620540Sfenner#define F_NOLOOP 0x0400 13720540Sfenner#define F_MTTL 0x0800 13820540Sfenner#define F_MIF 0x1000 13922417Sdanny#define F_AUDIBLE 0x2000 14055505Sshin#ifdef IPSEC 14155505Sshin#ifdef IPSEC_POLICY_IPSEC 14255505Sshin#define F_POLICY 0x4000 14355505Sshin#endif /*IPSEC_POLICY_IPSEC*/ 14455505Sshin#endif /*IPSEC*/ 14574029Sru#define F_TTL 0x8000 14677119Sphk#define F_MISSED 0x10000 147104339Sdd#define F_ONCE 0x20000 148109731Smaxim#define F_HDRINCL 0x40000 149110009Smdodd#define F_MASK 0x80000 150111765Smdodd#define F_TIME 0x100000 151149086Sglebius#define F_SWEEP 0x200000 152157535Sglebius#define F_WAITTIME 0x400000 1531558Srgrimes 1541558Srgrimes/* 1551558Srgrimes * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 1561558Srgrimes * number of received sequence numbers we can keep track of. Change 128 1571558Srgrimes * to 8192 for complete accuracy... 1581558Srgrimes */ 1591558Srgrimes#define MAX_DUP_CHK (8 * 128) 160273295Shrsstatic int mx_dup_ck = MAX_DUP_CHK; 161273295Shrsstatic char rcvd_tbl[MAX_DUP_CHK / 8]; 1621558Srgrimes 163273295Shrsstatic struct sockaddr_in whereto; /* who to ping */ 164273295Shrsstatic int datalen = DEFDATALEN; 165273295Shrsstatic int maxpayload; 166273295Shrsstatic int ssend; /* send socket file descriptor */ 167273295Shrsstatic int srecv; /* receive socket file descriptor */ 168273295Shrsstatic u_char outpackhdr[IP_MAXPACKET], *outpack; 169273295Shrsstatic char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ 170273295Shrsstatic char BSPACE = '\b'; /* characters written for flood */ 171273295Shrsstatic char DOT = '.'; 172273295Shrsstatic char *hostname; 173273295Shrsstatic char *shostname; 174273295Shrsstatic int ident; /* process id to identify our packets */ 175273295Shrsstatic int uid; /* cached uid for micro-optimization */ 176273295Shrsstatic u_char icmp_type = ICMP_ECHO; 177273295Shrsstatic u_char icmp_type_rsp = ICMP_ECHOREPLY; 178273295Shrsstatic int phdr_len = 0; 179273295Shrsstatic int send_len; 1801558Srgrimes 1811558Srgrimes/* counters */ 182273295Shrsstatic long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 183273295Shrsstatic long npackets; /* max packets to transmit */ 184273295Shrsstatic long nreceived; /* # of packets we got back */ 185273295Shrsstatic long nrepeats; /* number of duplicates */ 186273295Shrsstatic long ntransmitted; /* sequence # for outbound packets = #sent */ 187273295Shrsstatic long snpackets; /* max packets to transmit in one sweep */ 188273295Shrsstatic long sntransmitted; /* # of packets we sent in this sweep */ 189273295Shrsstatic int sweepmax; /* max value of payload in sweep */ 190273295Shrsstatic int sweepmin = 0; /* start value of payload in sweep */ 191273295Shrsstatic int sweepincr = 1; /* payload increment in sweep */ 192273295Shrsstatic int interval = 1000; /* interval between packets, ms */ 193273295Shrsstatic int waittime = MAXWAIT; /* timeout for each packet */ 194273295Shrsstatic long nrcvtimeout = 0; /* # of packets we got back after waittime */ 1951558Srgrimes 1961558Srgrimes/* timing */ 197273295Shrsstatic int timing; /* flag to do timing */ 198273295Shrsstatic double tmin = 999999999.0; /* minimum round trip time */ 199273295Shrsstatic double tmax = 0.0; /* maximum round trip time */ 200273295Shrsstatic double tsum = 0.0; /* sum of all times, for doing average */ 201273295Shrsstatic double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ 2021558Srgrimes 203273295Shrs/* nonzero if we've been told to finish up */ 204273295Shrsstatic volatile sig_atomic_t finish_up; 205273295Shrsstatic volatile sig_atomic_t siginfo_p; 2063792Ssef 207296047Soshogbo#ifdef HAVE_LIBCASPER 208261498Spjdstatic cap_channel_t *capdns; 209261498Spjd#endif 210261498Spjd 21123247Swollmanstatic void fill(char *, char *); 21223247Swollmanstatic u_short in_cksum(u_short *, int); 213296047Soshogbo#ifdef HAVE_LIBCASPER 214261498Spjdstatic cap_channel_t *capdns_setup(void); 215261498Spjd#endif 21623247Swollmanstatic void check_status(void); 21727533Sbdestatic void finish(void) __dead2; 21823247Swollmanstatic void pinger(void); 21923247Swollmanstatic char *pr_addr(struct in_addr); 220111765Smdoddstatic char *pr_ntime(n_time); 22123247Swollmanstatic void pr_icmph(struct icmp *); 22223247Swollmanstatic void pr_iph(struct ip *); 22336378Sfennerstatic void pr_pack(char *, int, struct sockaddr_in *, struct timeval *); 22423247Swollmanstatic void pr_retip(struct ip *); 22523247Swollmanstatic void status(int); 22627533Sbdestatic void stopit(int); 227209366Sedstatic void tvsub(struct timeval *, const struct timeval *); 22837671Scharnierstatic void usage(void) __dead2; 2291558Srgrimes 23023247Swollmanint 231209366Sedmain(int argc, char *const *argv) 2321558Srgrimes{ 233111932Sseanc struct sockaddr_in from, sock_in; 23493035Sobrien struct in_addr ifaddr; 235109733Smaxim struct timeval last, intvl; 23693035Sobrien struct iovec iov; 237109731Smaxim struct ip *ip; 23893035Sobrien struct msghdr msg; 23993035Sobrien struct sigaction si_sa; 240109731Smaxim size_t sz; 241169833Scognet u_char *datap, packet[IP_MAXPACKET] __aligned(4); 242110054Smdodd char *ep, *source, *target, *payload; 243109733Smaxim struct hostent *hp; 24493035Sobrien#ifdef IPSEC_POLICY_IPSEC 24593035Sobrien char *policy_in, *policy_out; 24693035Sobrien#endif 247109733Smaxim struct sockaddr_in *to; 248109733Smaxim double t; 249341714Seugen u_long alarmtimeout; 250341714Seugen long ltmp; 251261498Spjd int almost_done, ch, df, hold, i, icmp_len, mib[4], preload; 252261498Spjd int ssend_errno, srecv_errno, tos, ttl; 25393035Sobrien char ctrl[CMSG_SPACE(sizeof(struct timeval))]; 25493035Sobrien char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; 2551558Srgrimes#ifdef IP_OPTIONS 25699447Smaxim char rspace[MAX_IPOPTLEN]; /* record route space */ 2571558Srgrimes#endif 258109733Smaxim unsigned char loop, mttl; 25993035Sobrien 260111932Sseanc payload = source = NULL; 26155505Sshin#ifdef IPSEC_POLICY_IPSEC 26293035Sobrien policy_in = policy_out = NULL; 26355505Sshin#endif 264261498Spjd cap_rights_t rights; 265261498Spjd bool cansandbox; 2661558Srgrimes 26717474Sfenner /* 26817474Sfenner * Do the stuff that we need root priv's for *first*, and 26917474Sfenner * then drop our setuid bit. Save error reporting for 27017474Sfenner * after arg parsing. 271261498Spjd * 272261498Spjd * Historicaly ping was using one socket 's' for sending and for 273261498Spjd * receiving. After capsicum(4) related changes we use two 274261498Spjd * sockets. It was done for special ping use case - when user 275261498Spjd * issue ping on multicast or broadcast address replies come 276261498Spjd * from different addresses, not from the address we 277261498Spjd * connect(2)'ed to, and send socket do not receive those 278261498Spjd * packets. 27917474Sfenner */ 280261498Spjd ssend = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 281261498Spjd ssend_errno = errno; 282261498Spjd srecv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 283261498Spjd srecv_errno = errno; 28417474Sfenner 285241852Seadler if (setuid(getuid()) != 0) 286241852Seadler err(EX_NOPERM, "setuid() failed"); 28723295Simp uid = getuid(); 28817474Sfenner 289299516Struckman if (ssend < 0) { 290299516Struckman errno = ssend_errno; 291299516Struckman err(EX_OSERR, "ssend socket"); 292299516Struckman } 293299516Struckman 294299516Struckman if (srecv < 0) { 295299516Struckman errno = srecv_errno; 296299516Struckman err(EX_OSERR, "srecv socket"); 297299516Struckman } 298299516Struckman 299109731Smaxim alarmtimeout = df = preload = tos = 0; 3003792Ssef 301109731Smaxim outpack = outpackhdr + sizeof(struct ip); 30274029Sru while ((ch = getopt(argc, argv, 303157535Sglebius "Aac:DdfG:g:h:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:" 30474029Sru#ifdef IPSEC 30555505Sshin#ifdef IPSEC_POLICY_IPSEC 30674029Sru "P:" 30755505Sshin#endif /*IPSEC_POLICY_IPSEC*/ 30874029Sru#endif /*IPSEC*/ 30974029Sru )) != -1) 31055505Sshin { 3111558Srgrimes switch(ch) { 31277119Sphk case 'A': 31377119Sphk options |= F_MISSED; 31477119Sphk break; 31522417Sdanny case 'a': 31622417Sdanny options |= F_AUDIBLE; 31722417Sdanny break; 3181558Srgrimes case 'c': 319341714Seugen ltmp = strtol(optarg, &ep, 0); 320342143Seugen if (*ep || ep == optarg || ltmp <= 0) 32123247Swollman errx(EX_USAGE, 32223247Swollman "invalid count of packets to transmit: `%s'", 32323247Swollman optarg); 324341714Seugen npackets = ltmp; 3251558Srgrimes break; 326109731Smaxim case 'D': 327109731Smaxim options |= F_HDRINCL; 328109731Smaxim df = 1; 329109731Smaxim break; 3301558Srgrimes case 'd': 3311558Srgrimes options |= F_SO_DEBUG; 3321558Srgrimes break; 3331558Srgrimes case 'f': 33438549Sdillon if (uid) { 33523247Swollman errno = EPERM; 33623247Swollman err(EX_NOPERM, "-f flag"); 3371558Srgrimes } 3381558Srgrimes options |= F_FLOOD; 3391558Srgrimes setbuf(stdout, (char *)NULL); 3401558Srgrimes break; 341149086Sglebius case 'G': /* Maximum packet size for ping sweep */ 342341714Seugen ltmp = strtol(optarg, &ep, 0); 343341714Seugen if (*ep || ep == optarg || ltmp <= 0) 344149086Sglebius errx(EX_USAGE, "invalid packet size: `%s'", 345149086Sglebius optarg); 346341714Seugen if (uid != 0 && ltmp > DEFDATALEN) { 347149086Sglebius errno = EPERM; 348149086Sglebius err(EX_NOPERM, 349341714Seugen "packet size too large: %ld > %u", 350341714Seugen ltmp, DEFDATALEN); 351149086Sglebius } 352149086Sglebius options |= F_SWEEP; 353341714Seugen sweepmax = ltmp; 354149086Sglebius break; 355149086Sglebius case 'g': /* Minimum packet size for ping sweep */ 356341714Seugen ltmp = strtol(optarg, &ep, 0); 357341714Seugen if (*ep || ep == optarg || ltmp <= 0) 358149086Sglebius errx(EX_USAGE, "invalid packet size: `%s'", 359149086Sglebius optarg); 360341714Seugen if (uid != 0 && ltmp > DEFDATALEN) { 361149086Sglebius errno = EPERM; 362149086Sglebius err(EX_NOPERM, 363341714Seugen "packet size too large: %ld > %u", 364341714Seugen ltmp, DEFDATALEN); 365149086Sglebius } 366149086Sglebius options |= F_SWEEP; 367341714Seugen sweepmin = ltmp; 368149086Sglebius break; 369149086Sglebius case 'h': /* Packet size increment for ping sweep */ 370341714Seugen ltmp = strtol(optarg, &ep, 0); 371341714Seugen if (*ep || ep == optarg || ltmp < 1) 372149086Sglebius errx(EX_USAGE, "invalid increment size: `%s'", 373149086Sglebius optarg); 374341714Seugen if (uid != 0 && ltmp > DEFDATALEN) { 375149086Sglebius errno = EPERM; 376149086Sglebius err(EX_NOPERM, 377341714Seugen "packet size too large: %ld > %u", 378341714Seugen ltmp, DEFDATALEN); 379149086Sglebius } 380149086Sglebius options |= F_SWEEP; 381341714Seugen sweepincr = ltmp; 382149086Sglebius break; 383111287Sru case 'I': /* multicast interface */ 384111287Sru if (inet_aton(optarg, &ifaddr) == 0) 385111287Sru errx(EX_USAGE, 386111287Sru "invalid multicast interface: `%s'", 387111287Sru optarg); 388111287Sru options |= F_MIF; 389111287Sru break; 3901558Srgrimes case 'i': /* wait between sending packets */ 39193638Smaxim t = strtod(optarg, &ep) * 1000.0; 39293638Smaxim if (*ep || ep == optarg || t > (double)INT_MAX) 39393638Smaxim errx(EX_USAGE, "invalid timing interval: `%s'", 39493638Smaxim optarg); 39593638Smaxim options |= F_INTERVAL; 39693638Smaxim interval = (int)t; 39793638Smaxim if (uid && interval < 1000) { 39893638Smaxim errno = EPERM; 39993638Smaxim err(EX_NOPERM, "-i interval too short"); 40038549Sdillon } 4011558Srgrimes break; 402111287Sru case 'L': 403111287Sru options |= F_NOLOOP; 404111287Sru loop = 0; 40520540Sfenner break; 4061558Srgrimes case 'l': 407341714Seugen ltmp = strtol(optarg, &ep, 0); 408341714Seugen if (*ep || ep == optarg || ltmp > INT_MAX || ltmp < 0) 40993638Smaxim errx(EX_USAGE, 41093638Smaxim "invalid preload value: `%s'", optarg); 41146643Smckay if (uid) { 41223251Simp errno = EPERM; 41323251Simp err(EX_NOPERM, "-l flag"); 41423251Simp } 415341714Seugen preload = ltmp; 4161558Srgrimes break; 417111287Sru case 'M': 418111765Smdodd switch(optarg[0]) { 419111765Smdodd case 'M': 420111765Smdodd case 'm': 421111765Smdodd options |= F_MASK; 422111765Smdodd break; 423111765Smdodd case 'T': 424111765Smdodd case 't': 425111765Smdodd options |= F_TIME; 426111765Smdodd break; 427111765Smdodd default: 428111765Smdodd errx(EX_USAGE, "invalid message: `%c'", optarg[0]); 429111765Smdodd break; 430111765Smdodd } 43120540Sfenner break; 43274029Sru case 'm': /* TTL */ 433341714Seugen ltmp = strtol(optarg, &ep, 0); 434341714Seugen if (*ep || ep == optarg || ltmp > MAXTTL || ltmp < 0) 43593638Smaxim errx(EX_USAGE, "invalid TTL: `%s'", optarg); 436341714Seugen ttl = ltmp; 43774029Sru options |= F_TTL; 43874029Sru break; 4391558Srgrimes case 'n': 4401558Srgrimes options |= F_NUMERIC; 4411558Srgrimes break; 442104339Sdd case 'o': 443104339Sdd options |= F_ONCE; 444104339Sdd break; 445111287Sru#ifdef IPSEC 446111287Sru#ifdef IPSEC_POLICY_IPSEC 447111287Sru case 'P': 448111287Sru options |= F_POLICY; 449111287Sru if (!strncmp("in", optarg, 2)) 450111287Sru policy_in = strdup(optarg); 451111287Sru else if (!strncmp("out", optarg, 3)) 452111287Sru policy_out = strdup(optarg); 453111287Sru else 454111287Sru errx(1, "invalid security policy"); 455111287Sru break; 456111287Sru#endif /*IPSEC_POLICY_IPSEC*/ 457111287Sru#endif /*IPSEC*/ 4581558Srgrimes case 'p': /* fill buffer with user pattern */ 4591558Srgrimes options |= F_PINGFILLED; 460110054Smdodd payload = optarg; 461109733Smaxim break; 46217724Sfenner case 'Q': 46317724Sfenner options |= F_QUIET2; 46417724Sfenner break; 4651558Srgrimes case 'q': 4661558Srgrimes options |= F_QUIET; 4671558Srgrimes break; 4681558Srgrimes case 'R': 4691558Srgrimes options |= F_RROUTE; 4701558Srgrimes break; 4711558Srgrimes case 'r': 4721558Srgrimes options |= F_SO_DONTROUTE; 4731558Srgrimes break; 474111287Sru case 'S': 475111287Sru source = optarg; 476111287Sru break; 4771558Srgrimes case 's': /* size of packet to send */ 478341714Seugen ltmp = strtol(optarg, &ep, 0); 479341714Seugen if (*ep || ep == optarg || ltmp < 0) 48093638Smaxim errx(EX_USAGE, "invalid packet size: `%s'", 48193638Smaxim optarg); 482341714Seugen if (uid != 0 && ltmp > DEFDATALEN) { 483109734Smaxim errno = EPERM; 484109734Smaxim err(EX_NOPERM, 485341714Seugen "packet size too large: %ld > %u", 486341714Seugen ltmp, DEFDATALEN); 487109734Smaxim } 488341714Seugen datalen = ltmp; 4891558Srgrimes break; 490111287Sru case 'T': /* multicast TTL */ 491341714Seugen ltmp = strtol(optarg, &ep, 0); 492341714Seugen if (*ep || ep == optarg || ltmp > MAXTTL || ltmp < 0) 493111287Sru errx(EX_USAGE, "invalid multicast TTL: `%s'", 494111287Sru optarg); 495341714Seugen mttl = ltmp; 496111287Sru options |= F_MTTL; 49742337Simp break; 49855996Sbillf case 't': 49956342Sbillf alarmtimeout = strtoul(optarg, &ep, 0); 50056342Sbillf if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) 50155996Sbillf errx(EX_USAGE, "invalid timeout: `%s'", 50255996Sbillf optarg); 50356342Sbillf if (alarmtimeout > MAXALARM) 50456342Sbillf errx(EX_USAGE, "invalid timeout: `%s' > %d", 50556342Sbillf optarg, MAXALARM); 50656342Sbillf alarm((int)alarmtimeout); 50755996Sbillf break; 5081558Srgrimes case 'v': 5091558Srgrimes options |= F_VERBOSE; 5101558Srgrimes break; 511157535Sglebius case 'W': /* wait ms for answer */ 512157535Sglebius t = strtod(optarg, &ep); 513157535Sglebius if (*ep || ep == optarg || t > (double)INT_MAX) 514157535Sglebius errx(EX_USAGE, "invalid timing interval: `%s'", 515157535Sglebius optarg); 516157535Sglebius options |= F_WAITTIME; 517157535Sglebius waittime = (int)t; 518157535Sglebius break; 519109731Smaxim case 'z': 520109731Smaxim options |= F_HDRINCL; 521341714Seugen ltmp = strtol(optarg, &ep, 0); 522341714Seugen if (*ep || ep == optarg || ltmp > MAXTOS || ltmp < 0) 523109731Smaxim errx(EX_USAGE, "invalid TOS: `%s'", optarg); 524341714Seugen tos = ltmp; 525109731Smaxim break; 5261558Srgrimes default: 52737671Scharnier usage(); 5281558Srgrimes } 52923247Swollman } 5301558Srgrimes 53123247Swollman if (argc - optind != 1) 53237671Scharnier usage(); 53323247Swollman target = argv[optind]; 5341558Srgrimes 535112568Smdodd switch (options & (F_MASK|F_TIME)) { 536112568Smdodd case 0: break; 537112568Smdodd case F_MASK: 538111765Smdodd icmp_type = ICMP_MASKREQ; 539111765Smdodd icmp_type_rsp = ICMP_MASKREPLY; 540112568Smdodd phdr_len = MASK_LEN; 541111765Smdodd if (!(options & F_QUIET)) 542111765Smdodd (void)printf("ICMP_MASKREQ\n"); 543112568Smdodd break; 544112568Smdodd case F_TIME: 545111765Smdodd icmp_type = ICMP_TSTAMP; 546111765Smdodd icmp_type_rsp = ICMP_TSTAMPREPLY; 547112568Smdodd phdr_len = TS_LEN; 548111765Smdodd if (!(options & F_QUIET)) 549111765Smdodd (void)printf("ICMP_TSTAMP\n"); 550112568Smdodd break; 551112568Smdodd default: 552112568Smdodd errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive."); 553112568Smdodd break; 554111765Smdodd } 555117549Smaxim icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len; 556109734Smaxim if (options & F_RROUTE) 557117548Smaxim icmp_len += MAX_IPOPTLEN; 558117548Smaxim maxpayload = IP_MAXPACKET - icmp_len; 559109734Smaxim if (datalen > maxpayload) 560112531Sbde errx(EX_USAGE, "packet size too large: %d > %d", datalen, 561109734Smaxim maxpayload); 562117548Smaxim send_len = icmp_len + datalen; 563117549Smaxim datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN]; 564110054Smdodd if (options & F_PINGFILLED) { 565110054Smdodd fill((char *)datap, payload); 566110054Smdodd } 567296047Soshogbo#ifdef HAVE_LIBCASPER 568261498Spjd capdns = capdns_setup(); 569261498Spjd#endif 57042337Simp if (source) { 571111932Sseanc bzero((char *)&sock_in, sizeof(sock_in)); 572111932Sseanc sock_in.sin_family = AF_INET; 573111932Sseanc if (inet_aton(source, &sock_in.sin_addr) != 0) { 57442337Simp shostname = source; 57542337Simp } else { 576296047Soshogbo#ifdef HAVE_LIBCASPER 577261498Spjd if (capdns != NULL) 578261498Spjd hp = cap_gethostbyname2(capdns, source, 579261498Spjd AF_INET); 580261498Spjd else 581261498Spjd#endif 582261498Spjd hp = gethostbyname2(source, AF_INET); 58342337Simp if (!hp) 58442337Simp errx(EX_NOHOST, "cannot resolve %s: %s", 58593638Smaxim source, hstrerror(h_errno)); 58642337Simp 587111932Sseanc sock_in.sin_len = sizeof sock_in; 588111932Sseanc if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) || 58999447Smaxim hp->h_length < 0) 59093638Smaxim errx(1, "gethostbyname2: illegal address"); 591111932Sseanc memcpy(&sock_in.sin_addr, hp->h_addr_list[0], 592111932Sseanc sizeof(sock_in.sin_addr)); 59393638Smaxim (void)strncpy(snamebuf, hp->h_name, 59493638Smaxim sizeof(snamebuf) - 1); 59542337Simp snamebuf[sizeof(snamebuf) - 1] = '\0'; 59642337Simp shostname = snamebuf; 59742337Simp } 598261498Spjd if (bind(ssend, (struct sockaddr *)&sock_in, sizeof sock_in) == 599261498Spjd -1) 60042337Simp err(1, "bind"); 60142337Simp } 60242337Simp 60379403Smjacob bzero(&whereto, sizeof(whereto)); 60479403Smjacob to = &whereto; 6051558Srgrimes to->sin_family = AF_INET; 60679403Smjacob to->sin_len = sizeof *to; 60723247Swollman if (inet_aton(target, &to->sin_addr) != 0) { 6081558Srgrimes hostname = target; 60923247Swollman } else { 610296047Soshogbo#ifdef HAVE_LIBCASPER 611261498Spjd if (capdns != NULL) 612261498Spjd hp = cap_gethostbyname2(capdns, target, AF_INET); 613261498Spjd else 614261498Spjd#endif 615261498Spjd hp = gethostbyname2(target, AF_INET); 61623247Swollman if (!hp) 61723247Swollman errx(EX_NOHOST, "cannot resolve %s: %s", 61893638Smaxim target, hstrerror(h_errno)); 61923247Swollman 620111932Sseanc if ((unsigned)hp->h_length > sizeof(to->sin_addr)) 62193638Smaxim errx(1, "gethostbyname2 returned an illegal address"); 62223247Swollman memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr); 6231558Srgrimes (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 62431956Simp hnamebuf[sizeof(hnamebuf) - 1] = '\0'; 6251558Srgrimes hostname = hnamebuf; 6261558Srgrimes } 6271558Srgrimes 628296047Soshogbo#ifdef HAVE_LIBCASPER 629261498Spjd /* From now on we will use only reverse DNS lookups. */ 630261498Spjd if (capdns != NULL) { 631261498Spjd const char *types[1]; 632261498Spjd 633261498Spjd types[0] = "ADDR"; 634261498Spjd if (cap_dns_type_limit(capdns, types, 1) < 0) 635261498Spjd err(1, "unable to limit access to system.dns service"); 636261498Spjd } 637261498Spjd#endif 638261498Spjd 639261498Spjd if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0) 640261498Spjd err(1, "connect"); 641261498Spjd 64223247Swollman if (options & F_FLOOD && options & F_INTERVAL) 64323247Swollman errx(EX_USAGE, "-f and -i: incompatible options"); 6441558Srgrimes 64523247Swollman if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 64693638Smaxim errx(EX_USAGE, 64793638Smaxim "-f flag cannot be used with multicast destination"); 64823247Swollman if (options & (F_MIF | F_NOLOOP | F_MTTL) 64923247Swollman && !IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 65093638Smaxim errx(EX_USAGE, 65193638Smaxim "-I, -L, -T flags cannot be used with unicast destination"); 65223247Swollman 653112568Smdodd if (datalen >= TIMEVAL_LEN) /* can we time transfer */ 6541558Srgrimes timing = 1; 65523247Swollman 6561558Srgrimes if (!(options & F_PINGFILLED)) 657112568Smdodd for (i = TIMEVAL_LEN; i < datalen; ++i) 6581558Srgrimes *datap++ = i; 6591558Srgrimes 6601558Srgrimes ident = getpid() & 0xFFFF; 6611558Srgrimes 6621558Srgrimes hold = 1; 663261498Spjd if (options & F_SO_DEBUG) { 664261498Spjd (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold, 6651558Srgrimes sizeof(hold)); 666261498Spjd (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold, 667261498Spjd sizeof(hold)); 668261498Spjd } 6691558Srgrimes if (options & F_SO_DONTROUTE) 670261498Spjd (void)setsockopt(ssend, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 6711558Srgrimes sizeof(hold)); 67255505Sshin#ifdef IPSEC 67355505Sshin#ifdef IPSEC_POLICY_IPSEC 67455505Sshin if (options & F_POLICY) { 67555505Sshin char *buf; 67655505Sshin if (policy_in != NULL) { 67755505Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 67855505Sshin if (buf == NULL) 67968905Skris errx(EX_CONFIG, "%s", ipsec_strerror()); 680261498Spjd if (setsockopt(srecv, IPPROTO_IP, IP_IPSEC_POLICY, 68155505Sshin buf, ipsec_get_policylen(buf)) < 0) 68293638Smaxim err(EX_CONFIG, 68393638Smaxim "ipsec policy cannot be configured"); 68455505Sshin free(buf); 68555505Sshin } 6861558Srgrimes 68755505Sshin if (policy_out != NULL) { 68855505Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 68955505Sshin if (buf == NULL) 69068905Skris errx(EX_CONFIG, "%s", ipsec_strerror()); 691261498Spjd if (setsockopt(ssend, IPPROTO_IP, IP_IPSEC_POLICY, 69255505Sshin buf, ipsec_get_policylen(buf)) < 0) 69393638Smaxim err(EX_CONFIG, 69493638Smaxim "ipsec policy cannot be configured"); 69555505Sshin free(buf); 69655505Sshin } 69755505Sshin } 69855505Sshin#endif /*IPSEC_POLICY_IPSEC*/ 69955505Sshin#endif /*IPSEC*/ 70055505Sshin 701109731Smaxim if (options & F_HDRINCL) { 702109731Smaxim ip = (struct ip*)outpackhdr; 703109731Smaxim if (!(options & (F_TTL | F_MTTL))) { 704109731Smaxim mib[0] = CTL_NET; 705109731Smaxim mib[1] = PF_INET; 706109731Smaxim mib[2] = IPPROTO_IP; 707109731Smaxim mib[3] = IPCTL_DEFTTL; 708109731Smaxim sz = sizeof(ttl); 709109731Smaxim if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) 710109731Smaxim err(1, "sysctl(net.inet.ip.ttl)"); 711109731Smaxim } 712261498Spjd setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); 713109731Smaxim ip->ip_v = IPVERSION; 714109731Smaxim ip->ip_hl = sizeof(struct ip) >> 2; 715109731Smaxim ip->ip_tos = tos; 716109731Smaxim ip->ip_id = 0; 717277562Sae ip->ip_off = htons(df ? IP_DF : 0); 718109731Smaxim ip->ip_ttl = ttl; 719109731Smaxim ip->ip_p = IPPROTO_ICMP; 720111932Sseanc ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; 721109731Smaxim ip->ip_dst = to->sin_addr; 722109731Smaxim } 723261498Spjd 724261498Spjd if (options & F_NUMERIC) 725261498Spjd cansandbox = true; 726296047Soshogbo#ifdef HAVE_LIBCASPER 727261498Spjd else if (capdns != NULL) 728261498Spjd cansandbox = true; 729261498Spjd#endif 730261498Spjd else 731261498Spjd cansandbox = false; 732261498Spjd 733261498Spjd /* 734261498Spjd * Here we enter capability mode. Further down access to global 735261498Spjd * namespaces (e.g filesystem) is restricted (see capsicum(4)). 736261498Spjd * We must connect(2) our socket before this point. 737261498Spjd */ 738261498Spjd if (cansandbox && cap_enter() < 0 && errno != ENOSYS) 739261498Spjd err(1, "cap_enter"); 740261498Spjd 741261498Spjd cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); 742261498Spjd if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS) 743261498Spjd err(1, "cap_rights_limit srecv"); 744261498Spjd 745261498Spjd cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); 746261498Spjd if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS) 747261498Spjd err(1, "cap_rights_limit ssend"); 748261498Spjd 7491558Srgrimes /* record route option */ 7501558Srgrimes if (options & F_RROUTE) { 7511558Srgrimes#ifdef IP_OPTIONS 75236378Sfenner bzero(rspace, sizeof(rspace)); 7531558Srgrimes rspace[IPOPT_OPTVAL] = IPOPT_RR; 75436378Sfenner rspace[IPOPT_OLEN] = sizeof(rspace) - 1; 7551558Srgrimes rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 75636378Sfenner rspace[sizeof(rspace) - 1] = IPOPT_EOL; 757261498Spjd if (setsockopt(ssend, IPPROTO_IP, IP_OPTIONS, rspace, 75823247Swollman sizeof(rspace)) < 0) 75923247Swollman err(EX_OSERR, "setsockopt IP_OPTIONS"); 7601558Srgrimes#else 76123247Swollman errx(EX_UNAVAILABLE, 76293638Smaxim "record route not available in this implementation"); 7631558Srgrimes#endif /* IP_OPTIONS */ 7641558Srgrimes } 7651558Srgrimes 76674029Sru if (options & F_TTL) { 767261498Spjd if (setsockopt(ssend, IPPROTO_IP, IP_TTL, &ttl, 76874029Sru sizeof(ttl)) < 0) { 76974029Sru err(EX_OSERR, "setsockopt IP_TTL"); 77074029Sru } 77174029Sru } 77220540Sfenner if (options & F_NOLOOP) { 773261498Spjd if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, 77420540Sfenner sizeof(loop)) < 0) { 77523247Swollman err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); 77620540Sfenner } 77720540Sfenner } 77820540Sfenner if (options & F_MTTL) { 779261498Spjd if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, 78074029Sru sizeof(mttl)) < 0) { 78123247Swollman err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); 78220540Sfenner } 78320540Sfenner } 78420540Sfenner if (options & F_MIF) { 785261498Spjd if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, 78620540Sfenner sizeof(ifaddr)) < 0) { 78723247Swollman err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); 78820540Sfenner } 78920540Sfenner } 79036378Sfenner#ifdef SO_TIMESTAMP 79136378Sfenner { int on = 1; 792261498Spjd if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) 79336378Sfenner err(EX_OSERR, "setsockopt SO_TIMESTAMP"); 79436378Sfenner } 79536378Sfenner#endif 796149086Sglebius if (sweepmax) { 797296683Sglebius if (sweepmin > sweepmax) 798297027Smaxim errx(EX_USAGE, "Maximum packet size must be no less than the minimum packet size"); 79920540Sfenner 800149086Sglebius if (datalen != DEFDATALEN) 801149086Sglebius errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive"); 802149086Sglebius 803149086Sglebius if (npackets > 0) { 804149086Sglebius snpackets = npackets; 805149086Sglebius npackets = 0; 806149086Sglebius } else 807149086Sglebius snpackets = 1; 808149086Sglebius datalen = sweepmin; 809149086Sglebius send_len = icmp_len + sweepmin; 810149086Sglebius } 811296662Smaxim if (options & F_SWEEP && !sweepmax) 812149086Sglebius errx(EX_USAGE, "Maximum sweep size must be specified"); 813149086Sglebius 8141558Srgrimes /* 8151558Srgrimes * When pinging the broadcast address, you can get a lot of answers. 8161558Srgrimes * Doing something so evil is useful if you are trying to stress the 8171558Srgrimes * ethernet, or just want to fill the arp cache to get some stuff for 81823247Swollman * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast 81923247Swollman * or multicast pings if they wish. 8201558Srgrimes */ 82199447Smaxim 82299447Smaxim /* 82399447Smaxim * XXX receive buffer needs undetermined space for mbuf overhead 82499447Smaxim * as well. 82599447Smaxim */ 82699447Smaxim hold = IP_MAXPACKET + 128; 827261498Spjd (void)setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 8281558Srgrimes sizeof(hold)); 829261498Spjd /* CAP_SETSOCKOPT removed */ 830261498Spjd cap_rights_init(&rights, CAP_RECV, CAP_EVENT); 831261498Spjd if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS) 832261498Spjd err(1, "cap_rights_limit srecv setsockopt"); 833109733Smaxim if (uid == 0) 834261498Spjd (void)setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, (char *)&hold, 83579018Srwatson sizeof(hold)); 836261498Spjd /* CAP_SETSOCKOPT removed */ 837261498Spjd cap_rights_init(&rights, CAP_SEND); 838261498Spjd if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS) 839261498Spjd err(1, "cap_rights_limit ssend setsockopt"); 84079018Srwatson 84142337Simp if (to->sin_family == AF_INET) { 84242337Simp (void)printf("PING %s (%s)", hostname, 84342337Simp inet_ntoa(to->sin_addr)); 84442337Simp if (source) 84542337Simp (void)printf(" from %s", shostname); 846149086Sglebius if (sweepmax) 847149086Sglebius (void)printf(": (%d ... %d) data bytes\n", 848149086Sglebius sweepmin, sweepmax); 849296662Smaxim else 850149086Sglebius (void)printf(": %d data bytes\n", datalen); 851296662Smaxim 852149086Sglebius } else { 853149086Sglebius if (sweepmax) 854149086Sglebius (void)printf("PING %s: (%d ... %d) data bytes\n", 855149086Sglebius hostname, sweepmin, sweepmax); 856149086Sglebius else 857149086Sglebius (void)printf("PING %s: %d data bytes\n", hostname, datalen); 858149086Sglebius } 8591558Srgrimes 86020280Sbde /* 86127354Ssef * Use sigaction() instead of signal() to get unambiguous semantics, 86227354Ssef * in particular with SA_RESTART not set. 86320280Sbde */ 86427354Ssef 86520205Spst sigemptyset(&si_sa.sa_mask); 86620195Ssef si_sa.sa_flags = 0; 86727354Ssef 86827354Ssef si_sa.sa_handler = stopit; 86927354Ssef if (sigaction(SIGINT, &si_sa, 0) == -1) { 87027354Ssef err(EX_OSERR, "sigaction SIGINT"); 87127354Ssef } 87227354Ssef 87327354Ssef si_sa.sa_handler = status; 87420195Ssef if (sigaction(SIGINFO, &si_sa, 0) == -1) { 87523385Simp err(EX_OSERR, "sigaction"); 87620195Ssef } 87720195Ssef 87856342Sbillf if (alarmtimeout > 0) { 87956342Sbillf si_sa.sa_handler = stopit; 88056342Sbillf if (sigaction(SIGALRM, &si_sa, 0) == -1) 88156342Sbillf err(EX_OSERR, "sigaction SIGALRM"); 88256342Sbillf } 88356342Sbillf 88436378Sfenner bzero(&msg, sizeof(msg)); 88536378Sfenner msg.msg_name = (caddr_t)&from; 88636378Sfenner msg.msg_iov = &iov; 88736378Sfenner msg.msg_iovlen = 1; 88836378Sfenner#ifdef SO_TIMESTAMP 88936378Sfenner msg.msg_control = (caddr_t)ctrl; 89036378Sfenner#endif 89136378Sfenner iov.iov_base = packet; 892117548Smaxim iov.iov_len = IP_MAXPACKET; 89336378Sfenner 89489349Sru if (preload == 0) 89589349Sru pinger(); /* send the first ping */ 89689349Sru else { 89789349Sru if (npackets != 0 && preload > npackets) 89889349Sru preload = npackets; 89989349Sru while (preload--) /* fire off them quickies */ 90089349Sru pinger(); 90189349Sru } 90289349Sru (void)gettimeofday(&last, NULL); 9031558Srgrimes 90436378Sfenner if (options & F_FLOOD) { 90536378Sfenner intvl.tv_sec = 0; 90636378Sfenner intvl.tv_usec = 10000; 90736378Sfenner } else { 90838549Sdillon intvl.tv_sec = interval / 1000; 90938549Sdillon intvl.tv_usec = interval % 1000 * 1000; 91036378Sfenner } 9111558Srgrimes 912109733Smaxim almost_done = 0; 91327533Sbde while (!finish_up) { 914109733Smaxim struct timeval now, timeout; 91536378Sfenner fd_set rfds; 916109733Smaxim int cc, n; 9171558Srgrimes 91820280Sbde check_status(); 919261498Spjd if ((unsigned)srecv >= FD_SETSIZE) 920103146Snectar errx(EX_OSERR, "descriptor too large"); 92136378Sfenner FD_ZERO(&rfds); 922261498Spjd FD_SET(srecv, &rfds); 92336378Sfenner (void)gettimeofday(&now, NULL); 92436378Sfenner timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; 92536378Sfenner timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; 92636378Sfenner while (timeout.tv_usec < 0) { 92736378Sfenner timeout.tv_usec += 1000000; 92836378Sfenner timeout.tv_sec--; 9291558Srgrimes } 93037671Scharnier while (timeout.tv_usec >= 1000000) { 93136378Sfenner timeout.tv_usec -= 1000000; 93236378Sfenner timeout.tv_sec++; 93336378Sfenner } 93436378Sfenner if (timeout.tv_sec < 0) 935237942Sdelphij timerclear(&timeout); 936261498Spjd n = select(srecv + 1, &rfds, NULL, NULL, &timeout); 93746643Smckay if (n < 0) 93846643Smckay continue; /* Must be EINTR. */ 93936378Sfenner if (n == 1) { 940111932Sseanc struct timeval *tv = NULL; 94136378Sfenner#ifdef SO_TIMESTAMP 94236378Sfenner struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; 94336378Sfenner 94436378Sfenner msg.msg_controllen = sizeof(ctrl); 94536378Sfenner#endif 94636378Sfenner msg.msg_namelen = sizeof(from); 947261498Spjd if ((cc = recvmsg(srecv, &msg, 0)) < 0) { 94836378Sfenner if (errno == EINTR) 94936378Sfenner continue; 95037671Scharnier warn("recvmsg"); 9511558Srgrimes continue; 95236378Sfenner } 95336378Sfenner#ifdef SO_TIMESTAMP 95436378Sfenner if (cmsg->cmsg_level == SOL_SOCKET && 95536378Sfenner cmsg->cmsg_type == SCM_TIMESTAMP && 956111932Sseanc cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) { 95736713Sjb /* Copy to avoid alignment problems: */ 958103229Speter memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); 959111932Sseanc tv = &now; 96036713Sjb } 96136378Sfenner#endif 962111932Sseanc if (tv == NULL) { 96336378Sfenner (void)gettimeofday(&now, NULL); 964111932Sseanc tv = &now; 96536378Sfenner } 966111932Sseanc pr_pack((char *)packet, cc, &from, tv); 967111932Sseanc if ((options & F_ONCE && nreceived) || 968111932Sseanc (npackets && nreceived >= npackets)) 96936378Sfenner break; 9701558Srgrimes } 97146643Smckay if (n == 0 || options & F_FLOOD) { 972149086Sglebius if (sweepmax && sntransmitted == snpackets) { 973296662Smaxim for (i = 0; i < sweepincr ; ++i) 974149086Sglebius *datap++ = i; 975149086Sglebius datalen += sweepincr; 976149086Sglebius if (datalen > sweepmax) 977149086Sglebius break; 978149086Sglebius send_len = icmp_len + datalen; 979149086Sglebius sntransmitted = 0; 980296662Smaxim } 98136378Sfenner if (!npackets || ntransmitted < npackets) 98236378Sfenner pinger(); 98336378Sfenner else { 98436378Sfenner if (almost_done) 98536378Sfenner break; 98636378Sfenner almost_done = 1; 98746643Smckay intvl.tv_usec = 0; 98836378Sfenner if (nreceived) { 98936378Sfenner intvl.tv_sec = 2 * tmax / 1000; 99036378Sfenner if (!intvl.tv_sec) 99136378Sfenner intvl.tv_sec = 1; 992157535Sglebius } else { 993157535Sglebius intvl.tv_sec = waittime / 1000; 994157535Sglebius intvl.tv_usec = waittime % 1000 * 1000; 995157535Sglebius } 99636378Sfenner } 99736378Sfenner (void)gettimeofday(&last, NULL); 99883940Siedowse if (ntransmitted - nreceived - 1 > nmissedmax) { 99983940Siedowse nmissedmax = ntransmitted - nreceived - 1; 100083940Siedowse if (options & F_MISSED) 100183940Siedowse (void)write(STDOUT_FILENO, &BBELL, 1); 100283940Siedowse } 100336378Sfenner } 10041558Srgrimes } 100527533Sbde finish(); 10061558Srgrimes /* NOTREACHED */ 100723251Simp exit(0); /* Make the compiler happy */ 10081558Srgrimes} 10091558Srgrimes 10101558Srgrimes/* 101127533Sbde * stopit -- 101227533Sbde * Set the global bit that causes the main loop to quit. 101327533Sbde * Do NOT call finish() from here, since finish() does far too much 101427533Sbde * to be called from a signal handler. 101527299Sjulian */ 101627299Sjulianvoid 1017209366Sedstopit(int sig __unused) 101827299Sjulian{ 101993035Sobrien 1020125605Siedowse /* 1021125605Siedowse * When doing reverse DNS lookups, the finish_up flag might not 1022125605Siedowse * be noticed for a while. Just exit if we get a second SIGINT. 1023125605Siedowse */ 1024125605Siedowse if (!(options & F_NUMERIC) && finish_up) 1025125605Siedowse _exit(nreceived ? 0 : 2); 102627299Sjulian finish_up = 1; 102727299Sjulian} 102827299Sjulian 102927299Sjulian/* 10301558Srgrimes * pinger -- 10311558Srgrimes * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 10321558Srgrimes * will be added on by the kernel. The ID field is our UNIX process ID, 1033111765Smdodd * and the sequence number is an ascending integer. The first TIMEVAL_LEN 103499447Smaxim * bytes of the data portion are used to hold a UNIX "timeval" struct in 103599447Smaxim * host byte-order, to compute the round-trip time. 10361558Srgrimes */ 103723247Swollmanstatic void 103823247Swollmanpinger(void) 10391558Srgrimes{ 1040111765Smdodd struct timeval now; 1041135957Smaxim struct tv32 tv32; 1042109731Smaxim struct ip *ip; 104392806Sobrien struct icmp *icp; 104493035Sobrien int cc, i; 1045109731Smaxim u_char *packet; 10461558Srgrimes 1047109731Smaxim packet = outpack; 10481558Srgrimes icp = (struct icmp *)outpack; 1049111765Smdodd icp->icmp_type = icmp_type; 10501558Srgrimes icp->icmp_code = 0; 10511558Srgrimes icp->icmp_cksum = 0; 105291432Sfenner icp->icmp_seq = htons(ntransmitted); 10531558Srgrimes icp->icmp_id = ident; /* ID */ 10541558Srgrimes 105591432Sfenner CLR(ntransmitted % mx_dup_ck); 10561558Srgrimes 1057111765Smdodd if ((options & F_TIME) || timing) { 1058111765Smdodd (void)gettimeofday(&now, NULL); 10591558Srgrimes 1060135957Smaxim tv32.tv32_sec = htonl(now.tv_sec); 1061135957Smaxim tv32.tv32_usec = htonl(now.tv_usec); 1062111765Smdodd if (options & F_TIME) 1063111765Smdodd icp->icmp_otime = htonl((now.tv_sec % (24*60*60)) 1064111765Smdodd * 1000 + now.tv_usec / 1000); 1065111765Smdodd if (timing) 1066135957Smaxim bcopy((void *)&tv32, 1067117549Smaxim (void *)&outpack[ICMP_MINLEN + phdr_len], 1068135957Smaxim sizeof(tv32)); 1069111765Smdodd } 10701558Srgrimes 1071117549Smaxim cc = ICMP_MINLEN + phdr_len + datalen; 1072111765Smdodd 10731558Srgrimes /* compute ICMP checksum here */ 10741558Srgrimes icp->icmp_cksum = in_cksum((u_short *)icp, cc); 10751558Srgrimes 1076109731Smaxim if (options & F_HDRINCL) { 1077109731Smaxim cc += sizeof(struct ip); 1078109731Smaxim ip = (struct ip *)outpackhdr; 1079277562Sae ip->ip_len = htons(cc); 1080109731Smaxim ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); 1081109731Smaxim packet = outpackhdr; 1082109731Smaxim } 1083261498Spjd i = send(ssend, (char *)packet, cc, 0); 10841558Srgrimes if (i < 0 || i != cc) { 108523247Swollman if (i < 0) { 108627533Sbde if (options & F_FLOOD && errno == ENOBUFS) { 108727299Sjulian usleep(FLOOD_BACKOFF); 108827299Sjulian return; 108927299Sjulian } 109023247Swollman warn("sendto"); 109123247Swollman } else { 109223247Swollman warn("%s: partial write: %d of %d bytes", 109335216Sphk hostname, i, cc); 109423247Swollman } 109527945Sjulian } 109627945Sjulian ntransmitted++; 1097149086Sglebius sntransmitted++; 10981558Srgrimes if (!(options & F_QUIET) && options & F_FLOOD) 10991558Srgrimes (void)write(STDOUT_FILENO, &DOT, 1); 11001558Srgrimes} 11011558Srgrimes 11021558Srgrimes/* 11031558Srgrimes * pr_pack -- 11041558Srgrimes * Print out the packet, if it came from us. This logic is necessary 11051558Srgrimes * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 11061558Srgrimes * which arrive ('tis only fair). This permits multiple copies of this 11071558Srgrimes * program to be run without having intermingled output (or statistics!). 11081558Srgrimes */ 110923247Swollmanstatic void 1110209366Sedpr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) 11111558Srgrimes{ 1112103229Speter struct in_addr ina; 1113103229Speter u_char *cp, *dp; 111492806Sobrien struct icmp *icp; 111593035Sobrien struct ip *ip; 1116103227Speter const void *tp; 111793035Sobrien double triptime; 1118117548Smaxim int dupflag, hlen, i, j, recv_len, seq; 11191558Srgrimes static int old_rrlen; 11201558Srgrimes static char old_rr[MAX_IPOPTLEN]; 11211558Srgrimes 11221558Srgrimes /* Check the IP header */ 11231558Srgrimes ip = (struct ip *)buf; 11241558Srgrimes hlen = ip->ip_hl << 2; 1125117548Smaxim recv_len = cc; 11261558Srgrimes if (cc < hlen + ICMP_MINLEN) { 11271558Srgrimes if (options & F_VERBOSE) 112823247Swollman warn("packet too short (%d bytes) from %s", cc, 112923247Swollman inet_ntoa(from->sin_addr)); 11301558Srgrimes return; 11311558Srgrimes } 11321558Srgrimes 11331558Srgrimes /* Now the ICMP part */ 11341558Srgrimes cc -= hlen; 11351558Srgrimes icp = (struct icmp *)(buf + hlen); 1136111765Smdodd if (icp->icmp_type == icmp_type_rsp) { 11371558Srgrimes if (icp->icmp_id != ident) 11381558Srgrimes return; /* 'Twas not our ECHO */ 11391558Srgrimes ++nreceived; 114027533Sbde triptime = 0.0; 11411558Srgrimes if (timing) { 114236089Sjb struct timeval tv1; 1143135957Smaxim struct tv32 tv32; 11441558Srgrimes#ifndef icmp_data 1145103227Speter tp = &icp->icmp_ip; 11461558Srgrimes#else 1147103227Speter tp = icp->icmp_data; 11481558Srgrimes#endif 1149133723Sstefanf tp = (const char *)tp + phdr_len; 1150110009Smdodd 1151273295Shrs if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= 1152273295Shrs sizeof(tv1)) { 1153113217Smdodd /* Copy to avoid alignment problems: */ 1154135957Smaxim memcpy(&tv32, tp, sizeof(tv32)); 1155135957Smaxim tv1.tv_sec = ntohl(tv32.tv32_sec); 1156135957Smaxim tv1.tv_usec = ntohl(tv32.tv32_usec); 1157113217Smdodd tvsub(tv, &tv1); 1158113217Smdodd triptime = ((double)tv->tv_sec) * 1000.0 + 1159113217Smdodd ((double)tv->tv_usec) / 1000.0; 1160113217Smdodd tsum += triptime; 1161113217Smdodd tsumsq += triptime * triptime; 1162113217Smdodd if (triptime < tmin) 1163113217Smdodd tmin = triptime; 1164113217Smdodd if (triptime > tmax) 1165113217Smdodd tmax = triptime; 1166113217Smdodd } else 1167113217Smdodd timing = 0; 11681558Srgrimes } 11691558Srgrimes 117091432Sfenner seq = ntohs(icp->icmp_seq); 117191432Sfenner 117291432Sfenner if (TST(seq % mx_dup_ck)) { 11731558Srgrimes ++nrepeats; 11741558Srgrimes --nreceived; 11751558Srgrimes dupflag = 1; 11761558Srgrimes } else { 117791432Sfenner SET(seq % mx_dup_ck); 11781558Srgrimes dupflag = 0; 11791558Srgrimes } 11801558Srgrimes 11811558Srgrimes if (options & F_QUIET) 11821558Srgrimes return; 1183296662Smaxim 1184157535Sglebius if (options & F_WAITTIME && triptime > waittime) { 1185157535Sglebius ++nrcvtimeout; 1186157535Sglebius return; 1187157535Sglebius } 11881558Srgrimes 11891558Srgrimes if (options & F_FLOOD) 11901558Srgrimes (void)write(STDOUT_FILENO, &BSPACE, 1); 11911558Srgrimes else { 11921558Srgrimes (void)printf("%d bytes from %s: icmp_seq=%u", cc, 11931558Srgrimes inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 119491432Sfenner seq); 11951558Srgrimes (void)printf(" ttl=%d", ip->ip_ttl); 11961558Srgrimes if (timing) 11971859Sdg (void)printf(" time=%.3f ms", triptime); 11981558Srgrimes if (dupflag) 11991558Srgrimes (void)printf(" (DUP!)"); 120022417Sdanny if (options & F_AUDIBLE) 120177119Sphk (void)write(STDOUT_FILENO, &BBELL, 1); 1202110009Smdodd if (options & F_MASK) { 1203110009Smdodd /* Just prentend this cast isn't ugly */ 1204110009Smdodd (void)printf(" mask=%s", 1205297024Smaxim inet_ntoa(*(struct in_addr *)&(icp->icmp_mask))); 1206110009Smdodd } 1207111765Smdodd if (options & F_TIME) { 1208111765Smdodd (void)printf(" tso=%s", pr_ntime(icp->icmp_otime)); 1209111765Smdodd (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime)); 1210111765Smdodd (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime)); 1211111765Smdodd } 1212117548Smaxim if (recv_len != send_len) { 1213117548Smaxim (void)printf( 1214117548Smaxim "\nwrong total length %d instead of %d", 1215117548Smaxim recv_len, send_len); 1216117548Smaxim } 12171558Srgrimes /* check the data */ 1218111765Smdodd cp = (u_char*)&icp->icmp_data[phdr_len]; 1219117549Smaxim dp = &outpack[ICMP_MINLEN + phdr_len]; 1220113217Smdodd cc -= ICMP_MINLEN + phdr_len; 1221113463Smaxim i = 0; 1222113463Smaxim if (timing) { /* don't check variable timestamp */ 1223113463Smaxim cp += TIMEVAL_LEN; 1224113463Smaxim dp += TIMEVAL_LEN; 1225113463Smaxim cc -= TIMEVAL_LEN; 1226113463Smaxim i += TIMEVAL_LEN; 1227113463Smaxim } 1228113463Smaxim for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) { 12291558Srgrimes if (*cp != *dp) { 12301558Srgrimes (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 12311558Srgrimes i, *dp, *cp); 123293638Smaxim (void)printf("\ncp:"); 12331558Srgrimes cp = (u_char*)&icp->icmp_data[0]; 123436089Sjb for (i = 0; i < datalen; ++i, ++cp) { 1235117548Smaxim if ((i % 16) == 8) 12361558Srgrimes (void)printf("\n\t"); 1237117548Smaxim (void)printf("%2x ", *cp); 12381558Srgrimes } 123993638Smaxim (void)printf("\ndp:"); 1240117549Smaxim cp = &outpack[ICMP_MINLEN]; 124136089Sjb for (i = 0; i < datalen; ++i, ++cp) { 1242117548Smaxim if ((i % 16) == 8) 124336089Sjb (void)printf("\n\t"); 1244117548Smaxim (void)printf("%2x ", *cp); 124536089Sjb } 12461558Srgrimes break; 12471558Srgrimes } 12481558Srgrimes } 12491558Srgrimes } 12501558Srgrimes } else { 125117724Sfenner /* 125217724Sfenner * We've got something other than an ECHOREPLY. 125317724Sfenner * See if it's a reply to something that we sent. 125417724Sfenner * We can compare IP destination, protocol, 125517724Sfenner * and ICMP type and ID. 125623251Simp * 125723251Simp * Only print all the error messages if we are running 125893638Smaxim * as root to avoid leaking information not normally 125923251Simp * available to those not running as root. 126017724Sfenner */ 126117724Sfenner#ifndef icmp_data 126217724Sfenner struct ip *oip = &icp->icmp_ip; 126317724Sfenner#else 126417724Sfenner struct ip *oip = (struct ip *)icp->icmp_data; 126517724Sfenner#endif 126617724Sfenner struct icmp *oicmp = (struct icmp *)(oip + 1); 126717724Sfenner 126823295Simp if (((options & F_VERBOSE) && uid == 0) || 126917724Sfenner (!(options & F_QUIET2) && 127079403Smjacob (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) && 127117724Sfenner (oip->ip_p == IPPROTO_ICMP) && 127217724Sfenner (oicmp->icmp_type == ICMP_ECHO) && 127317724Sfenner (oicmp->icmp_id == ident))) { 127417724Sfenner (void)printf("%d bytes from %s: ", cc, 127523247Swollman pr_addr(from->sin_addr)); 127617724Sfenner pr_icmph(icp); 127717724Sfenner } else 127817724Sfenner return; 12791558Srgrimes } 12801558Srgrimes 12811558Srgrimes /* Display any IP options */ 12821558Srgrimes cp = (u_char *)buf + sizeof(struct ip); 12831558Srgrimes 12841558Srgrimes for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 12851558Srgrimes switch (*cp) { 12861558Srgrimes case IPOPT_EOL: 12871558Srgrimes hlen = 0; 12881558Srgrimes break; 12891558Srgrimes case IPOPT_LSRR: 1290109730Smaxim case IPOPT_SSRR: 1291109730Smaxim (void)printf(*cp == IPOPT_LSRR ? 1292109730Smaxim "\nLSRR: " : "\nSSRR: "); 129399446Smaxim j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1; 12941558Srgrimes hlen -= 2; 129599446Smaxim cp += 2; 1296105624Smaxim if (j >= INADDR_LEN && 1297105624Smaxim j <= hlen - (int)sizeof(struct ip)) { 12981558Srgrimes for (;;) { 129999446Smaxim bcopy(++cp, &ina.s_addr, INADDR_LEN); 130099446Smaxim if (ina.s_addr == 0) 130193638Smaxim (void)printf("\t0.0.0.0"); 130299446Smaxim else 130393638Smaxim (void)printf("\t%s", 130493638Smaxim pr_addr(ina)); 130599446Smaxim hlen -= INADDR_LEN; 130699446Smaxim cp += INADDR_LEN - 1; 130799446Smaxim j -= INADDR_LEN; 130899446Smaxim if (j < INADDR_LEN) 130999446Smaxim break; 131099446Smaxim (void)putchar('\n'); 131199446Smaxim } 131299446Smaxim } else 131399446Smaxim (void)printf("\t(truncated route)\n"); 13141558Srgrimes break; 13151558Srgrimes case IPOPT_RR: 131699446Smaxim j = cp[IPOPT_OLEN]; /* get length */ 131799446Smaxim i = cp[IPOPT_OFFSET]; /* and pointer */ 13181558Srgrimes hlen -= 2; 131999446Smaxim cp += 2; 13201558Srgrimes if (i > j) 13211558Srgrimes i = j; 132299446Smaxim i = i - IPOPT_MINOFF + 1; 132399446Smaxim if (i < 0 || i > (hlen - (int)sizeof(struct ip))) { 132499446Smaxim old_rrlen = 0; 13251558Srgrimes continue; 132699446Smaxim } 13271558Srgrimes if (i == old_rrlen 13281558Srgrimes && !bcmp((char *)cp, old_rr, i) 13291558Srgrimes && !(options & F_FLOOD)) { 13301558Srgrimes (void)printf("\t(same route)"); 13311558Srgrimes hlen -= i; 13321558Srgrimes cp += i; 13331558Srgrimes break; 13341558Srgrimes } 133599446Smaxim old_rrlen = i; 133699446Smaxim bcopy((char *)cp, old_rr, i); 13371558Srgrimes (void)printf("\nRR: "); 133899446Smaxim if (i >= INADDR_LEN && 133999446Smaxim i <= hlen - (int)sizeof(struct ip)) { 134099446Smaxim for (;;) { 134199446Smaxim bcopy(++cp, &ina.s_addr, INADDR_LEN); 134299446Smaxim if (ina.s_addr == 0) 134399446Smaxim (void)printf("\t0.0.0.0"); 134499446Smaxim else 134599446Smaxim (void)printf("\t%s", 134699446Smaxim pr_addr(ina)); 134799446Smaxim hlen -= INADDR_LEN; 134899446Smaxim cp += INADDR_LEN - 1; 134999446Smaxim i -= INADDR_LEN; 135099446Smaxim if (i < INADDR_LEN) 135199446Smaxim break; 135299446Smaxim (void)putchar('\n'); 135323247Swollman } 135499446Smaxim } else 135599446Smaxim (void)printf("\t(truncated route)"); 13561558Srgrimes break; 13571558Srgrimes case IPOPT_NOP: 13581558Srgrimes (void)printf("\nNOP"); 13591558Srgrimes break; 13601558Srgrimes default: 13611558Srgrimes (void)printf("\nunknown option %x", *cp); 13621558Srgrimes break; 13631558Srgrimes } 13641558Srgrimes if (!(options & F_FLOOD)) { 13651558Srgrimes (void)putchar('\n'); 13661558Srgrimes (void)fflush(stdout); 13671558Srgrimes } 13681558Srgrimes} 13691558Srgrimes 13701558Srgrimes/* 13711558Srgrimes * in_cksum -- 13721558Srgrimes * Checksum routine for Internet Protocol family headers (C Version) 13731558Srgrimes */ 137423247Swollmanu_short 1375209366Sedin_cksum(u_short *addr, int len) 13761558Srgrimes{ 137793035Sobrien int nleft, sum; 137893035Sobrien u_short *w; 137953191Spb union { 138053369Spb u_short us; 138153369Spb u_char uc[2]; 138253369Spb } last; 138353369Spb u_short answer; 13841558Srgrimes 138593035Sobrien nleft = len; 138693035Sobrien sum = 0; 138793035Sobrien w = addr; 138893035Sobrien 13891558Srgrimes /* 13901558Srgrimes * Our algorithm is simple, using a 32 bit accumulator (sum), we add 13911558Srgrimes * sequential 16 bit words to it, and at the end, fold back all the 13921558Srgrimes * carry bits from the top 16 bits into the lower 16 bits. 13931558Srgrimes */ 13941558Srgrimes while (nleft > 1) { 13951558Srgrimes sum += *w++; 13961558Srgrimes nleft -= 2; 13971558Srgrimes } 13981558Srgrimes 13991558Srgrimes /* mop up an odd byte, if necessary */ 14001558Srgrimes if (nleft == 1) { 140153369Spb last.uc[0] = *(u_char *)w; 140253369Spb last.uc[1] = 0; 140353369Spb sum += last.us; 14041558Srgrimes } 14051558Srgrimes 14061558Srgrimes /* add back carry outs from top 16 bits to low 16 bits */ 14071558Srgrimes sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 14081558Srgrimes sum += (sum >> 16); /* add carry */ 140953369Spb answer = ~sum; /* truncate to 16 bits */ 141053369Spb return(answer); 14111558Srgrimes} 14121558Srgrimes 14131558Srgrimes/* 14141558Srgrimes * tvsub -- 14151558Srgrimes * Subtract 2 timeval structs: out = out - in. Out is assumed to 14161558Srgrimes * be >= in. 14171558Srgrimes */ 141823247Swollmanstatic void 1419209366Sedtvsub(struct timeval *out, const struct timeval *in) 14201558Srgrimes{ 142193035Sobrien 14221558Srgrimes if ((out->tv_usec -= in->tv_usec) < 0) { 14231558Srgrimes --out->tv_sec; 14241558Srgrimes out->tv_usec += 1000000; 14251558Srgrimes } 14261558Srgrimes out->tv_sec -= in->tv_sec; 14271558Srgrimes} 14281558Srgrimes 14291558Srgrimes/* 14303792Ssef * status -- 14313792Ssef * Print out statistics when SIGINFO is received. 14323792Ssef */ 14333792Ssef 143423247Swollmanstatic void 1435209366Sedstatus(int sig __unused) 143620280Sbde{ 143793035Sobrien 143820195Ssef siginfo_p = 1; 143920195Ssef} 144020195Ssef 144123247Swollmanstatic void 1442209366Sedcheck_status(void) 14433792Ssef{ 144493035Sobrien 144520195Ssef if (siginfo_p) { 144620195Ssef siginfo_p = 0; 1447161273Sdd (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)", 144820280Sbde nreceived, ntransmitted, 1449115691Smaxim ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0); 1450115691Smaxim if (nreceived && timing) 1451115691Smaxim (void)fprintf(stderr, " %.3f min / %.3f avg / %.3f max", 1452115691Smaxim tmin, tsum / (nreceived + nrepeats), tmax); 1453115691Smaxim (void)fprintf(stderr, "\n"); 145420195Ssef } 14553792Ssef} 14563792Ssef 14573792Ssef/* 14581558Srgrimes * finish -- 14591558Srgrimes * Print out statistics, and give up. 14601558Srgrimes */ 146123247Swollmanstatic void 1462209366Sedfinish(void) 14631558Srgrimes{ 14641558Srgrimes 14651558Srgrimes (void)signal(SIGINT, SIG_IGN); 146627354Ssef (void)signal(SIGALRM, SIG_IGN); 14671558Srgrimes (void)putchar('\n'); 14681558Srgrimes (void)fflush(stdout); 14691558Srgrimes (void)printf("--- %s ping statistics ---\n", hostname); 14701558Srgrimes (void)printf("%ld packets transmitted, ", ntransmitted); 14711558Srgrimes (void)printf("%ld packets received, ", nreceived); 14721558Srgrimes if (nrepeats) 14731558Srgrimes (void)printf("+%ld duplicates, ", nrepeats); 147446080Simp if (ntransmitted) { 14751558Srgrimes if (nreceived > ntransmitted) 14761558Srgrimes (void)printf("-- somebody's printing up packets!"); 14771558Srgrimes else 1478161273Sdd (void)printf("%.1f%% packet loss", 1479161273Sdd ((ntransmitted - nreceived) * 100.0) / 1480161273Sdd ntransmitted); 148146080Simp } 1482157535Sglebius if (nrcvtimeout) 1483157535Sglebius (void)printf(", %ld packets out of wait time", nrcvtimeout); 14841558Srgrimes (void)putchar('\n'); 148527508Swollman if (nreceived && timing) { 148627508Swollman double n = nreceived + nrepeats; 148727508Swollman double avg = tsum / n; 148827508Swollman double vari = tsumsq / n - avg * avg; 148993638Smaxim (void)printf( 149093638Smaxim "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", 149127508Swollman tmin, avg, tmax, sqrt(vari)); 149227508Swollman } 14933792Ssef 14948871Srgrimes if (nreceived) 14954862Sdg exit(0); 14964862Sdg else 14974862Sdg exit(2); 14981558Srgrimes} 14991558Srgrimes 15001558Srgrimes#ifdef notdef 15011558Srgrimesstatic char *ttab[] = { 15021558Srgrimes "Echo Reply", /* ip + seq + udata */ 15031558Srgrimes "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 15041558Srgrimes "Source Quench", /* IP */ 15051558Srgrimes "Redirect", /* redirect type, gateway, + IP */ 15061558Srgrimes "Echo", 15071558Srgrimes "Time Exceeded", /* transit, frag reassem + IP */ 15081558Srgrimes "Parameter Problem", /* pointer + IP */ 15091558Srgrimes "Timestamp", /* id + seq + three timestamps */ 15101558Srgrimes "Timestamp Reply", /* " */ 15111558Srgrimes "Info Request", /* id + sq */ 15121558Srgrimes "Info Reply" /* " */ 15131558Srgrimes}; 15141558Srgrimes#endif 15151558Srgrimes 15161558Srgrimes/* 15171558Srgrimes * pr_icmph -- 15181558Srgrimes * Print a descriptive string about an ICMP header. 15191558Srgrimes */ 152023247Swollmanstatic void 1521209366Sedpr_icmph(struct icmp *icp) 15221558Srgrimes{ 152393035Sobrien 15241558Srgrimes switch(icp->icmp_type) { 15251558Srgrimes case ICMP_ECHOREPLY: 15261558Srgrimes (void)printf("Echo Reply\n"); 15271558Srgrimes /* XXX ID + Seq + Data */ 15281558Srgrimes break; 15291558Srgrimes case ICMP_UNREACH: 15301558Srgrimes switch(icp->icmp_code) { 15311558Srgrimes case ICMP_UNREACH_NET: 15321558Srgrimes (void)printf("Destination Net Unreachable\n"); 15331558Srgrimes break; 15341558Srgrimes case ICMP_UNREACH_HOST: 15351558Srgrimes (void)printf("Destination Host Unreachable\n"); 15361558Srgrimes break; 15371558Srgrimes case ICMP_UNREACH_PROTOCOL: 15381558Srgrimes (void)printf("Destination Protocol Unreachable\n"); 15391558Srgrimes break; 15401558Srgrimes case ICMP_UNREACH_PORT: 15411558Srgrimes (void)printf("Destination Port Unreachable\n"); 15421558Srgrimes break; 15431558Srgrimes case ICMP_UNREACH_NEEDFRAG: 154417724Sfenner (void)printf("frag needed and DF set (MTU %d)\n", 154528059Sfenner ntohs(icp->icmp_nextmtu)); 15461558Srgrimes break; 15471558Srgrimes case ICMP_UNREACH_SRCFAIL: 15481558Srgrimes (void)printf("Source Route Failed\n"); 15491558Srgrimes break; 155017724Sfenner case ICMP_UNREACH_FILTER_PROHIB: 155117724Sfenner (void)printf("Communication prohibited by filter\n"); 155217724Sfenner break; 15531558Srgrimes default: 15541558Srgrimes (void)printf("Dest Unreachable, Bad Code: %d\n", 15551558Srgrimes icp->icmp_code); 15561558Srgrimes break; 15571558Srgrimes } 15581558Srgrimes /* Print returned IP header information */ 15591558Srgrimes#ifndef icmp_data 15601558Srgrimes pr_retip(&icp->icmp_ip); 15611558Srgrimes#else 15621558Srgrimes pr_retip((struct ip *)icp->icmp_data); 15631558Srgrimes#endif 15641558Srgrimes break; 15651558Srgrimes case ICMP_SOURCEQUENCH: 15661558Srgrimes (void)printf("Source Quench\n"); 15671558Srgrimes#ifndef icmp_data 15681558Srgrimes pr_retip(&icp->icmp_ip); 15691558Srgrimes#else 15701558Srgrimes pr_retip((struct ip *)icp->icmp_data); 15711558Srgrimes#endif 15721558Srgrimes break; 15731558Srgrimes case ICMP_REDIRECT: 15741558Srgrimes switch(icp->icmp_code) { 15751558Srgrimes case ICMP_REDIRECT_NET: 15761558Srgrimes (void)printf("Redirect Network"); 15771558Srgrimes break; 15781558Srgrimes case ICMP_REDIRECT_HOST: 15791558Srgrimes (void)printf("Redirect Host"); 15801558Srgrimes break; 15811558Srgrimes case ICMP_REDIRECT_TOSNET: 15821558Srgrimes (void)printf("Redirect Type of Service and Network"); 15831558Srgrimes break; 15841558Srgrimes case ICMP_REDIRECT_TOSHOST: 15851558Srgrimes (void)printf("Redirect Type of Service and Host"); 15861558Srgrimes break; 15871558Srgrimes default: 15881558Srgrimes (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 15891558Srgrimes break; 15901558Srgrimes } 159128059Sfenner (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); 15921558Srgrimes#ifndef icmp_data 15931558Srgrimes pr_retip(&icp->icmp_ip); 15941558Srgrimes#else 15951558Srgrimes pr_retip((struct ip *)icp->icmp_data); 15961558Srgrimes#endif 15971558Srgrimes break; 15981558Srgrimes case ICMP_ECHO: 15991558Srgrimes (void)printf("Echo Request\n"); 16001558Srgrimes /* XXX ID + Seq + Data */ 16011558Srgrimes break; 16021558Srgrimes case ICMP_TIMXCEED: 16031558Srgrimes switch(icp->icmp_code) { 16041558Srgrimes case ICMP_TIMXCEED_INTRANS: 16051558Srgrimes (void)printf("Time to live exceeded\n"); 16061558Srgrimes break; 16071558Srgrimes case ICMP_TIMXCEED_REASS: 16081558Srgrimes (void)printf("Frag reassembly time exceeded\n"); 16091558Srgrimes break; 16101558Srgrimes default: 16111558Srgrimes (void)printf("Time exceeded, Bad Code: %d\n", 16121558Srgrimes icp->icmp_code); 16131558Srgrimes break; 16141558Srgrimes } 16151558Srgrimes#ifndef icmp_data 16161558Srgrimes pr_retip(&icp->icmp_ip); 16171558Srgrimes#else 16181558Srgrimes pr_retip((struct ip *)icp->icmp_data); 16191558Srgrimes#endif 16201558Srgrimes break; 16211558Srgrimes case ICMP_PARAMPROB: 16221558Srgrimes (void)printf("Parameter problem: pointer = 0x%02x\n", 16231558Srgrimes icp->icmp_hun.ih_pptr); 16241558Srgrimes#ifndef icmp_data 16251558Srgrimes pr_retip(&icp->icmp_ip); 16261558Srgrimes#else 16271558Srgrimes pr_retip((struct ip *)icp->icmp_data); 16281558Srgrimes#endif 16291558Srgrimes break; 16301558Srgrimes case ICMP_TSTAMP: 16311558Srgrimes (void)printf("Timestamp\n"); 16321558Srgrimes /* XXX ID + Seq + 3 timestamps */ 16331558Srgrimes break; 16341558Srgrimes case ICMP_TSTAMPREPLY: 16351558Srgrimes (void)printf("Timestamp Reply\n"); 16361558Srgrimes /* XXX ID + Seq + 3 timestamps */ 16371558Srgrimes break; 16381558Srgrimes case ICMP_IREQ: 16391558Srgrimes (void)printf("Information Request\n"); 16401558Srgrimes /* XXX ID + Seq */ 16411558Srgrimes break; 16421558Srgrimes case ICMP_IREQREPLY: 16431558Srgrimes (void)printf("Information Reply\n"); 16441558Srgrimes /* XXX ID + Seq */ 16451558Srgrimes break; 16461558Srgrimes case ICMP_MASKREQ: 16471558Srgrimes (void)printf("Address Mask Request\n"); 16481558Srgrimes break; 16491558Srgrimes case ICMP_MASKREPLY: 16501558Srgrimes (void)printf("Address Mask Reply\n"); 16511558Srgrimes break; 165217724Sfenner case ICMP_ROUTERADVERT: 165317724Sfenner (void)printf("Router Advertisement\n"); 165417724Sfenner break; 165517724Sfenner case ICMP_ROUTERSOLICIT: 165617724Sfenner (void)printf("Router Solicitation\n"); 165717724Sfenner break; 16581558Srgrimes default: 16591558Srgrimes (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 16601558Srgrimes } 16611558Srgrimes} 16621558Srgrimes 16631558Srgrimes/* 16641558Srgrimes * pr_iph -- 16651558Srgrimes * Print an IP header with options. 16661558Srgrimes */ 166723247Swollmanstatic void 1668209366Sedpr_iph(struct ip *ip) 16691558Srgrimes{ 1670311936Sdim struct in_addr ina; 167193035Sobrien u_char *cp; 16721558Srgrimes int hlen; 16731558Srgrimes 16741558Srgrimes hlen = ip->ip_hl << 2; 16751558Srgrimes cp = (u_char *)ip + 20; /* point to options */ 16761558Srgrimes 167717724Sfenner (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); 16781558Srgrimes (void)printf(" %1x %1x %02x %04x %04x", 167917724Sfenner ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 168017724Sfenner ntohs(ip->ip_id)); 168136089Sjb (void)printf(" %1lx %04lx", 168236089Sjb (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13, 168336089Sjb (u_long) ntohl(ip->ip_off) & 0x1fff); 168417724Sfenner (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 168517724Sfenner ntohs(ip->ip_sum)); 1686311936Sdim memcpy(&ina, &ip->ip_src.s_addr, sizeof ina); 1687311936Sdim (void)printf(" %s ", inet_ntoa(ina)); 1688311936Sdim memcpy(&ina, &ip->ip_dst.s_addr, sizeof ina); 1689311936Sdim (void)printf(" %s ", inet_ntoa(ina)); 169017724Sfenner /* dump any option bytes */ 16911558Srgrimes while (hlen-- > 20) { 16921558Srgrimes (void)printf("%02x", *cp++); 16931558Srgrimes } 16941558Srgrimes (void)putchar('\n'); 16951558Srgrimes} 16961558Srgrimes 16971558Srgrimes/* 16981558Srgrimes * pr_addr -- 16991558Srgrimes * Return an ascii host address as a dotted quad and optionally with 17001558Srgrimes * a hostname. 17011558Srgrimes */ 170223247Swollmanstatic char * 1703209366Sedpr_addr(struct in_addr ina) 17041558Srgrimes{ 17051558Srgrimes struct hostent *hp; 170623251Simp static char buf[16 + 3 + MAXHOSTNAMELEN]; 17071558Srgrimes 1708261498Spjd if (options & F_NUMERIC) 170923247Swollman return inet_ntoa(ina); 1710261498Spjd 1711296047Soshogbo#ifdef HAVE_LIBCASPER 1712261498Spjd if (capdns != NULL) 1713261498Spjd hp = cap_gethostbyaddr(capdns, (char *)&ina, 4, AF_INET); 17141558Srgrimes else 1715261498Spjd#endif 1716261498Spjd hp = gethostbyaddr((char *)&ina, 4, AF_INET); 1717261498Spjd 1718261498Spjd if (hp == NULL) 1719261498Spjd return inet_ntoa(ina); 1720261498Spjd 1721261498Spjd (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 1722261498Spjd inet_ntoa(ina)); 17231558Srgrimes return(buf); 17241558Srgrimes} 17251558Srgrimes 17261558Srgrimes/* 17271558Srgrimes * pr_retip -- 17281558Srgrimes * Dump some info on a returned (via ICMP) IP packet. 17291558Srgrimes */ 173023247Swollmanstatic void 1731209366Sedpr_retip(struct ip *ip) 17321558Srgrimes{ 173393035Sobrien u_char *cp; 17341558Srgrimes int hlen; 17351558Srgrimes 17361558Srgrimes pr_iph(ip); 17371558Srgrimes hlen = ip->ip_hl << 2; 17381558Srgrimes cp = (u_char *)ip + hlen; 17391558Srgrimes 17401558Srgrimes if (ip->ip_p == 6) 17411558Srgrimes (void)printf("TCP: from port %u, to port %u (decimal)\n", 17421558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 17431558Srgrimes else if (ip->ip_p == 17) 17441558Srgrimes (void)printf("UDP: from port %u, to port %u (decimal)\n", 17451558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 17461558Srgrimes} 17471558Srgrimes 1748111765Smdoddstatic char * 1749209366Sedpr_ntime(n_time timestamp) 1750111765Smdodd{ 1751111765Smdodd static char buf[10]; 1752117550Smaxim int hour, min, sec; 1753111765Smdodd 1754117550Smaxim sec = ntohl(timestamp) / 1000; 1755117550Smaxim hour = sec / 60 / 60; 1756117550Smaxim min = (sec % (60 * 60)) / 60; 1757117550Smaxim sec = (sec % (60 * 60)) % 60; 1758111765Smdodd 1759117550Smaxim (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec); 1760111765Smdodd 1761111765Smdodd return (buf); 1762111765Smdodd} 1763111765Smdodd 176423247Swollmanstatic void 1765209366Sedfill(char *bp, char *patp) 17661558Srgrimes{ 176793035Sobrien char *cp; 176893035Sobrien int pat[16]; 176999447Smaxim u_int ii, jj, kk; 17701558Srgrimes 177123247Swollman for (cp = patp; *cp; cp++) { 177223247Swollman if (!isxdigit(*cp)) 177393638Smaxim errx(EX_USAGE, 177493638Smaxim "patterns must be specified as hex digits"); 177593638Smaxim 177623247Swollman } 17771558Srgrimes ii = sscanf(patp, 17781558Srgrimes "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 17791558Srgrimes &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 17801558Srgrimes &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 17811558Srgrimes &pat[13], &pat[14], &pat[15]); 17821558Srgrimes 17831558Srgrimes if (ii > 0) 1784112568Smdodd for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii) 17851558Srgrimes for (jj = 0; jj < ii; ++jj) 17861558Srgrimes bp[jj + kk] = pat[jj]; 17871558Srgrimes if (!(options & F_QUIET)) { 17881558Srgrimes (void)printf("PATTERN: 0x"); 17891558Srgrimes for (jj = 0; jj < ii; ++jj) 17901558Srgrimes (void)printf("%02x", bp[jj] & 0xFF); 17911558Srgrimes (void)printf("\n"); 17921558Srgrimes } 17931558Srgrimes} 17941558Srgrimes 1795296047Soshogbo#ifdef HAVE_LIBCASPER 1796261498Spjdstatic cap_channel_t * 1797261498Spjdcapdns_setup(void) 1798261498Spjd{ 1799261498Spjd cap_channel_t *capcas, *capdnsloc; 1800261498Spjd const char *types[2]; 1801261498Spjd int families[1]; 1802261498Spjd 1803261498Spjd capcas = cap_init(); 1804296047Soshogbo if (capcas == NULL) 1805296047Soshogbo err(1, "unable to create casper process"); 1806261498Spjd capdnsloc = cap_service_open(capcas, "system.dns"); 1807261498Spjd /* Casper capability no longer needed. */ 1808261498Spjd cap_close(capcas); 1809261498Spjd if (capdnsloc == NULL) 1810261498Spjd err(1, "unable to open system.dns service"); 1811261498Spjd types[0] = "NAME"; 1812261498Spjd types[1] = "ADDR"; 1813261498Spjd if (cap_dns_type_limit(capdnsloc, types, 2) < 0) 1814261498Spjd err(1, "unable to limit access to system.dns service"); 1815261498Spjd families[0] = AF_INET; 1816261498Spjd if (cap_dns_family_limit(capdnsloc, families, 1) < 0) 1817261498Spjd err(1, "unable to limit access to system.dns service"); 1818261498Spjd 1819261498Spjd return (capdnsloc); 1820261498Spjd} 1821296047Soshogbo#endif /* HAVE_LIBCASPER */ 1822261498Spjd 1823112228Sru#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 1824112228Sru#define SECOPT " [-P policy]" 1825112228Sru#else 1826112228Sru#define SECOPT "" 1827112228Sru#endif 182823247Swollmanstatic void 1829209366Sedusage(void) 18301558Srgrimes{ 1831112228Sru 1832157535Sglebius (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 1833152996Sru"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]", 1834152996Sru" [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]", 1835152996Sru" " SECOPT " [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]", 1836157535Sglebius" [-W waittime] [-z tos] host", 1837112110Sru" ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]", 1838112228Sru" [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]", 1839157535Sglebius" [-s packetsize] [-T ttl] [-t timeout] [-W waittime]", 1840157535Sglebius" [-z tos] mcast-group"); 184123247Swollman exit(EX_USAGE); 18421558Srgrimes} 1843