ping.c revision 169833
11558Srgrimes/* 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: head/sbin/ping/ping.c 169833 2007-05-21 14:38:45Z cognet $"); 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> */ 66109733Smaxim#include <sys/socket.h> 67109731Smaxim#include <sys/sysctl.h> 68109733Smaxim#include <sys/time.h> 69109733Smaxim#include <sys/uio.h> 7023247Swollman 71109733Smaxim#include <netinet/in.h> 72109733Smaxim#include <netinet/in_systm.h> 73109733Smaxim#include <netinet/ip.h> 74109733Smaxim#include <netinet/ip_icmp.h> 75109733Smaxim#include <netinet/ip_var.h> 76109733Smaxim#include <arpa/inet.h> 77109733Smaxim 78109733Smaxim#ifdef IPSEC 79109733Smaxim#include <netinet6/ipsec.h> 80109733Smaxim#endif /*IPSEC*/ 81109733Smaxim 8223247Swollman#include <ctype.h> 8323247Swollman#include <err.h> 8423247Swollman#include <errno.h> 8527508Swollman#include <math.h> 8623247Swollman#include <netdb.h> 8723247Swollman#include <signal.h> 8823247Swollman#include <stdio.h> 8923247Swollman#include <stdlib.h> 9023247Swollman#include <string.h> 9123247Swollman#include <sysexits.h> 9223247Swollman#include <unistd.h> 9323247Swollman 9499446Smaxim#define INADDR_LEN ((int)sizeof(in_addr_t)) 95135957Smaxim#define TIMEVAL_LEN ((int)sizeof(struct tv32)) 96111765Smdodd#define MASK_LEN (ICMP_MASKLEN - ICMP_MINLEN) 97111765Smdodd#define TS_LEN (ICMP_TSLEN - ICMP_MINLEN) 98112729Smdodd#define DEFDATALEN 56 /* default data length */ 9927533Sbde#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */ 10027533Sbde /* runs out of buffer space */ 10199447Smaxim#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN) 10299447Smaxim#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN) 103157535Sglebius#define MAXWAIT 10000 /* max ms to wait for response */ 10456342Sbillf#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ 105109731Smaxim#define MAXTOS 255 1061558Srgrimes 1071558Srgrimes#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 1081558Srgrimes#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 1091558Srgrimes#define SET(bit) (A(bit) |= B(bit)) 1101558Srgrimes#define CLR(bit) (A(bit) &= (~B(bit))) 1111558Srgrimes#define TST(bit) (A(bit) & B(bit)) 1121558Srgrimes 113135957Smaximstruct tv32 { 114135957Smaxim int32_t tv32_sec; 115135957Smaxim int32_t tv32_usec; 116135957Smaxim}; 117135957Smaxim 1181558Srgrimes/* various options */ 1191558Srgrimesint options; 12020540Sfenner#define F_FLOOD 0x0001 12120540Sfenner#define F_INTERVAL 0x0002 12220540Sfenner#define F_NUMERIC 0x0004 12320540Sfenner#define F_PINGFILLED 0x0008 12420540Sfenner#define F_QUIET 0x0010 12520540Sfenner#define F_RROUTE 0x0020 12620540Sfenner#define F_SO_DEBUG 0x0040 12720540Sfenner#define F_SO_DONTROUTE 0x0080 12820540Sfenner#define F_VERBOSE 0x0100 12920540Sfenner#define F_QUIET2 0x0200 13020540Sfenner#define F_NOLOOP 0x0400 13120540Sfenner#define F_MTTL 0x0800 13220540Sfenner#define F_MIF 0x1000 13322417Sdanny#define F_AUDIBLE 0x2000 13455505Sshin#ifdef IPSEC 13555505Sshin#ifdef IPSEC_POLICY_IPSEC 13655505Sshin#define F_POLICY 0x4000 13755505Sshin#endif /*IPSEC_POLICY_IPSEC*/ 13855505Sshin#endif /*IPSEC*/ 13974029Sru#define F_TTL 0x8000 14077119Sphk#define F_MISSED 0x10000 141104339Sdd#define F_ONCE 0x20000 142109731Smaxim#define F_HDRINCL 0x40000 143110009Smdodd#define F_MASK 0x80000 144111765Smdodd#define F_TIME 0x100000 145149086Sglebius#define F_SWEEP 0x200000 146157535Sglebius#define F_WAITTIME 0x400000 1471558Srgrimes 1481558Srgrimes/* 1491558Srgrimes * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 1501558Srgrimes * number of received sequence numbers we can keep track of. Change 128 1511558Srgrimes * to 8192 for complete accuracy... 1521558Srgrimes */ 1531558Srgrimes#define MAX_DUP_CHK (8 * 128) 1541558Srgrimesint mx_dup_ck = MAX_DUP_CHK; 1551558Srgrimeschar rcvd_tbl[MAX_DUP_CHK / 8]; 1561558Srgrimes 15779403Smjacobstruct sockaddr_in whereto; /* who to ping */ 1581558Srgrimesint datalen = DEFDATALEN; 159112531Sbdeint maxpayload; 1601558Srgrimesint s; /* socket file descriptor */ 161109731Smaximu_char outpackhdr[IP_MAXPACKET], *outpack; 162109733Smaximchar BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ 1631558Srgrimeschar BSPACE = '\b'; /* characters written for flood */ 1641558Srgrimeschar DOT = '.'; 1651558Srgrimeschar *hostname; 16642337Simpchar *shostname; 1671558Srgrimesint ident; /* process id to identify our packets */ 16823295Simpint uid; /* cached uid for micro-optimization */ 169111765Smdoddu_char icmp_type = ICMP_ECHO; 170111765Smdoddu_char icmp_type_rsp = ICMP_ECHOREPLY; 171111765Smdoddint phdr_len = 0; 172117548Smaximint send_len; 1731558Srgrimes 1741558Srgrimes/* counters */ 175109733Smaximlong nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 1761558Srgrimeslong npackets; /* max packets to transmit */ 1771558Srgrimeslong nreceived; /* # of packets we got back */ 1781558Srgrimeslong nrepeats; /* number of duplicates */ 1791558Srgrimeslong ntransmitted; /* sequence # for outbound packets = #sent */ 180149086Sglebiuslong snpackets; /* max packets to transmit in one sweep */ 181149086Sglebiuslong snreceived; /* # of packets we got back in this sweep */ 182149086Sglebiuslong sntransmitted; /* # of packets we sent in this sweep */ 183149086Sglebiusint sweepmax; /* max value of payload in sweep */ 184149086Sglebiusint sweepmin = 0; /* start value of payload in sweep */ 185149086Sglebiusint sweepincr = 1; /* payload increment in sweep */ 18638549Sdillonint interval = 1000; /* interval between packets, ms */ 187157535Sglebiusint waittime = MAXWAIT; /* timeout for each packet */ 188157535Sglebiuslong nrcvtimeout = 0; /* # of packets we got back after waittime */ 1891558Srgrimes 1901558Srgrimes/* timing */ 1911558Srgrimesint timing; /* flag to do timing */ 1921558Srgrimesdouble tmin = 999999999.0; /* minimum round trip time */ 1931558Srgrimesdouble tmax = 0.0; /* maximum round trip time */ 1941558Srgrimesdouble tsum = 0.0; /* sum of all times, for doing average */ 19527508Swollmandouble tsumsq = 0.0; /* sum of all times squared, for std. dev. */ 1961558Srgrimes 19727533Sbdevolatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */ 19827533Sbdevolatile sig_atomic_t siginfo_p; 1993792Ssef 20023247Swollmanstatic void fill(char *, char *); 20123247Swollmanstatic u_short in_cksum(u_short *, int); 20223247Swollmanstatic void check_status(void); 20327533Sbdestatic void finish(void) __dead2; 20423247Swollmanstatic void pinger(void); 20523247Swollmanstatic char *pr_addr(struct in_addr); 206111765Smdoddstatic char *pr_ntime(n_time); 20723247Swollmanstatic void pr_icmph(struct icmp *); 20823247Swollmanstatic void pr_iph(struct ip *); 20936378Sfennerstatic void pr_pack(char *, int, struct sockaddr_in *, struct timeval *); 21023247Swollmanstatic void pr_retip(struct ip *); 21123247Swollmanstatic void status(int); 21227533Sbdestatic void stopit(int); 21323247Swollmanstatic void tvsub(struct timeval *, struct timeval *); 21437671Scharnierstatic void usage(void) __dead2; 2151558Srgrimes 21623247Swollmanint 2171558Srgrimesmain(argc, argv) 2181558Srgrimes int argc; 21923247Swollman char *const *argv; 2201558Srgrimes{ 221111932Sseanc struct sockaddr_in from, sock_in; 22293035Sobrien struct in_addr ifaddr; 223109733Smaxim struct timeval last, intvl; 22493035Sobrien struct iovec iov; 225109731Smaxim struct ip *ip; 22693035Sobrien struct msghdr msg; 22793035Sobrien struct sigaction si_sa; 228109731Smaxim size_t sz; 229169833Scognet u_char *datap, packet[IP_MAXPACKET] __aligned(4); 230110054Smdodd char *ep, *source, *target, *payload; 231109733Smaxim struct hostent *hp; 23293035Sobrien#ifdef IPSEC_POLICY_IPSEC 23393035Sobrien char *policy_in, *policy_out; 23493035Sobrien#endif 235109733Smaxim struct sockaddr_in *to; 236109733Smaxim double t; 23793035Sobrien u_long alarmtimeout, ultmp; 238117548Smaxim int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno, 239109733Smaxim tos, ttl; 24093035Sobrien char ctrl[CMSG_SPACE(sizeof(struct timeval))]; 24193035Sobrien char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; 2421558Srgrimes#ifdef IP_OPTIONS 24399447Smaxim char rspace[MAX_IPOPTLEN]; /* record route space */ 2441558Srgrimes#endif 245109733Smaxim unsigned char loop, mttl; 24693035Sobrien 247111932Sseanc payload = source = NULL; 24855505Sshin#ifdef IPSEC_POLICY_IPSEC 24993035Sobrien policy_in = policy_out = NULL; 25055505Sshin#endif 2511558Srgrimes 25217474Sfenner /* 25317474Sfenner * Do the stuff that we need root priv's for *first*, and 25417474Sfenner * then drop our setuid bit. Save error reporting for 25517474Sfenner * after arg parsing. 25617474Sfenner */ 25723247Swollman s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 25823247Swollman sockerrno = errno; 25917474Sfenner 26017474Sfenner setuid(getuid()); 26123295Simp uid = getuid(); 26217474Sfenner 263109731Smaxim alarmtimeout = df = preload = tos = 0; 2643792Ssef 265109731Smaxim outpack = outpackhdr + sizeof(struct ip); 26674029Sru while ((ch = getopt(argc, argv, 267157535Sglebius "Aac:DdfG:g:h:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:" 26874029Sru#ifdef IPSEC 26955505Sshin#ifdef IPSEC_POLICY_IPSEC 27074029Sru "P:" 27155505Sshin#endif /*IPSEC_POLICY_IPSEC*/ 27274029Sru#endif /*IPSEC*/ 27374029Sru )) != -1) 27455505Sshin { 2751558Srgrimes switch(ch) { 27677119Sphk case 'A': 27777119Sphk options |= F_MISSED; 27877119Sphk break; 27922417Sdanny case 'a': 28022417Sdanny options |= F_AUDIBLE; 28122417Sdanny break; 2821558Srgrimes case 'c': 28323247Swollman ultmp = strtoul(optarg, &ep, 0); 28423247Swollman if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp) 28523247Swollman errx(EX_USAGE, 28623247Swollman "invalid count of packets to transmit: `%s'", 28723247Swollman optarg); 28823247Swollman npackets = ultmp; 2891558Srgrimes break; 290109731Smaxim case 'D': 291109731Smaxim options |= F_HDRINCL; 292109731Smaxim df = 1; 293109731Smaxim break; 2941558Srgrimes case 'd': 2951558Srgrimes options |= F_SO_DEBUG; 2961558Srgrimes break; 2971558Srgrimes case 'f': 29838549Sdillon if (uid) { 29923247Swollman errno = EPERM; 30023247Swollman err(EX_NOPERM, "-f flag"); 3011558Srgrimes } 3021558Srgrimes options |= F_FLOOD; 3031558Srgrimes setbuf(stdout, (char *)NULL); 3041558Srgrimes break; 305149086Sglebius case 'G': /* Maximum packet size for ping sweep */ 306149086Sglebius ultmp = strtoul(optarg, &ep, 0); 307149086Sglebius if (*ep || ep == optarg) 308149086Sglebius errx(EX_USAGE, "invalid packet size: `%s'", 309149086Sglebius optarg); 310149086Sglebius if (uid != 0 && ultmp > DEFDATALEN) { 311149086Sglebius errno = EPERM; 312149086Sglebius err(EX_NOPERM, 313149086Sglebius "packet size too large: %lu > %u", 314149086Sglebius ultmp, DEFDATALEN); 315149086Sglebius } 316149086Sglebius options |= F_SWEEP; 317149086Sglebius sweepmax = ultmp; 318149086Sglebius break; 319149086Sglebius case 'g': /* Minimum packet size for ping sweep */ 320149086Sglebius ultmp = strtoul(optarg, &ep, 0); 321149086Sglebius if (*ep || ep == optarg) 322149086Sglebius errx(EX_USAGE, "invalid packet size: `%s'", 323149086Sglebius optarg); 324149086Sglebius if (uid != 0 && ultmp > DEFDATALEN) { 325149086Sglebius errno = EPERM; 326149086Sglebius err(EX_NOPERM, 327149086Sglebius "packet size too large: %lu > %u", 328149086Sglebius ultmp, DEFDATALEN); 329149086Sglebius } 330149086Sglebius options |= F_SWEEP; 331149086Sglebius sweepmin = ultmp; 332149086Sglebius break; 333149086Sglebius case 'h': /* Packet size increment for ping sweep */ 334149086Sglebius ultmp = strtoul(optarg, &ep, 0); 335149086Sglebius if (*ep || ep == optarg || ultmp < 1) 336149086Sglebius errx(EX_USAGE, "invalid increment size: `%s'", 337149086Sglebius optarg); 338149086Sglebius if (uid != 0 && ultmp > DEFDATALEN) { 339149086Sglebius errno = EPERM; 340149086Sglebius err(EX_NOPERM, 341149086Sglebius "packet size too large: %lu > %u", 342149086Sglebius ultmp, DEFDATALEN); 343149086Sglebius } 344149086Sglebius options |= F_SWEEP; 345149086Sglebius sweepincr = ultmp; 346149086Sglebius break; 347111287Sru case 'I': /* multicast interface */ 348111287Sru if (inet_aton(optarg, &ifaddr) == 0) 349111287Sru errx(EX_USAGE, 350111287Sru "invalid multicast interface: `%s'", 351111287Sru optarg); 352111287Sru options |= F_MIF; 353111287Sru break; 3541558Srgrimes case 'i': /* wait between sending packets */ 35593638Smaxim t = strtod(optarg, &ep) * 1000.0; 35693638Smaxim if (*ep || ep == optarg || t > (double)INT_MAX) 35793638Smaxim errx(EX_USAGE, "invalid timing interval: `%s'", 35893638Smaxim optarg); 35993638Smaxim options |= F_INTERVAL; 36093638Smaxim interval = (int)t; 36193638Smaxim if (uid && interval < 1000) { 36293638Smaxim errno = EPERM; 36393638Smaxim err(EX_NOPERM, "-i interval too short"); 36438549Sdillon } 3651558Srgrimes break; 366111287Sru case 'L': 367111287Sru options |= F_NOLOOP; 368111287Sru loop = 0; 36920540Sfenner break; 3701558Srgrimes case 'l': 37123247Swollman ultmp = strtoul(optarg, &ep, 0); 37223247Swollman if (*ep || ep == optarg || ultmp > INT_MAX) 37393638Smaxim errx(EX_USAGE, 37493638Smaxim "invalid preload value: `%s'", optarg); 37546643Smckay if (uid) { 37623251Simp errno = EPERM; 37723251Simp err(EX_NOPERM, "-l flag"); 37823251Simp } 37923247Swollman preload = ultmp; 3801558Srgrimes break; 381111287Sru case 'M': 382111765Smdodd switch(optarg[0]) { 383111765Smdodd case 'M': 384111765Smdodd case 'm': 385111765Smdodd options |= F_MASK; 386111765Smdodd break; 387111765Smdodd case 'T': 388111765Smdodd case 't': 389111765Smdodd options |= F_TIME; 390111765Smdodd break; 391111765Smdodd default: 392111765Smdodd errx(EX_USAGE, "invalid message: `%c'", optarg[0]); 393111765Smdodd break; 394111765Smdodd } 39520540Sfenner break; 39674029Sru case 'm': /* TTL */ 39774029Sru ultmp = strtoul(optarg, &ep, 0); 398109732Smaxim if (*ep || ep == optarg || ultmp > MAXTTL) 39993638Smaxim errx(EX_USAGE, "invalid TTL: `%s'", optarg); 40074029Sru ttl = ultmp; 40174029Sru options |= F_TTL; 40274029Sru break; 4031558Srgrimes case 'n': 4041558Srgrimes options |= F_NUMERIC; 4051558Srgrimes break; 406104339Sdd case 'o': 407104339Sdd options |= F_ONCE; 408104339Sdd break; 409111287Sru#ifdef IPSEC 410111287Sru#ifdef IPSEC_POLICY_IPSEC 411111287Sru case 'P': 412111287Sru options |= F_POLICY; 413111287Sru if (!strncmp("in", optarg, 2)) 414111287Sru policy_in = strdup(optarg); 415111287Sru else if (!strncmp("out", optarg, 3)) 416111287Sru policy_out = strdup(optarg); 417111287Sru else 418111287Sru errx(1, "invalid security policy"); 419111287Sru break; 420111287Sru#endif /*IPSEC_POLICY_IPSEC*/ 421111287Sru#endif /*IPSEC*/ 4221558Srgrimes case 'p': /* fill buffer with user pattern */ 4231558Srgrimes options |= F_PINGFILLED; 424110054Smdodd payload = optarg; 425109733Smaxim break; 42617724Sfenner case 'Q': 42717724Sfenner options |= F_QUIET2; 42817724Sfenner break; 4291558Srgrimes case 'q': 4301558Srgrimes options |= F_QUIET; 4311558Srgrimes break; 4321558Srgrimes case 'R': 4331558Srgrimes options |= F_RROUTE; 4341558Srgrimes break; 4351558Srgrimes case 'r': 4361558Srgrimes options |= F_SO_DONTROUTE; 4371558Srgrimes break; 438111287Sru case 'S': 439111287Sru source = optarg; 440111287Sru break; 4411558Srgrimes case 's': /* size of packet to send */ 44223247Swollman ultmp = strtoul(optarg, &ep, 0); 44399447Smaxim if (*ep || ep == optarg) 44493638Smaxim errx(EX_USAGE, "invalid packet size: `%s'", 44593638Smaxim optarg); 446109734Smaxim if (uid != 0 && ultmp > DEFDATALEN) { 447109734Smaxim errno = EPERM; 448109734Smaxim err(EX_NOPERM, 449109734Smaxim "packet size too large: %lu > %u", 450109734Smaxim ultmp, DEFDATALEN); 451109734Smaxim } 45223247Swollman datalen = ultmp; 4531558Srgrimes break; 454111287Sru case 'T': /* multicast TTL */ 455111287Sru ultmp = strtoul(optarg, &ep, 0); 456111287Sru if (*ep || ep == optarg || ultmp > MAXTTL) 457111287Sru errx(EX_USAGE, "invalid multicast TTL: `%s'", 458111287Sru optarg); 459111287Sru mttl = ultmp; 460111287Sru options |= F_MTTL; 46142337Simp break; 46255996Sbillf case 't': 46356342Sbillf alarmtimeout = strtoul(optarg, &ep, 0); 46456342Sbillf if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) 46555996Sbillf errx(EX_USAGE, "invalid timeout: `%s'", 46655996Sbillf optarg); 46756342Sbillf if (alarmtimeout > MAXALARM) 46856342Sbillf errx(EX_USAGE, "invalid timeout: `%s' > %d", 46956342Sbillf optarg, MAXALARM); 47056342Sbillf alarm((int)alarmtimeout); 47155996Sbillf break; 4721558Srgrimes case 'v': 4731558Srgrimes options |= F_VERBOSE; 4741558Srgrimes break; 475157535Sglebius case 'W': /* wait ms for answer */ 476157535Sglebius t = strtod(optarg, &ep); 477157535Sglebius if (*ep || ep == optarg || t > (double)INT_MAX) 478157535Sglebius errx(EX_USAGE, "invalid timing interval: `%s'", 479157535Sglebius optarg); 480157535Sglebius options |= F_WAITTIME; 481157535Sglebius waittime = (int)t; 482157535Sglebius break; 483109731Smaxim case 'z': 484109731Smaxim options |= F_HDRINCL; 485109731Smaxim ultmp = strtoul(optarg, &ep, 0); 486109731Smaxim if (*ep || ep == optarg || ultmp > MAXTOS) 487109731Smaxim errx(EX_USAGE, "invalid TOS: `%s'", optarg); 488109731Smaxim tos = ultmp; 489109731Smaxim break; 4901558Srgrimes default: 49137671Scharnier usage(); 4921558Srgrimes } 49323247Swollman } 4941558Srgrimes 49523247Swollman if (argc - optind != 1) 49637671Scharnier usage(); 49723247Swollman target = argv[optind]; 4981558Srgrimes 499112568Smdodd switch (options & (F_MASK|F_TIME)) { 500112568Smdodd case 0: break; 501112568Smdodd case F_MASK: 502111765Smdodd icmp_type = ICMP_MASKREQ; 503111765Smdodd icmp_type_rsp = ICMP_MASKREPLY; 504112568Smdodd phdr_len = MASK_LEN; 505111765Smdodd if (!(options & F_QUIET)) 506111765Smdodd (void)printf("ICMP_MASKREQ\n"); 507112568Smdodd break; 508112568Smdodd case F_TIME: 509111765Smdodd icmp_type = ICMP_TSTAMP; 510111765Smdodd icmp_type_rsp = ICMP_TSTAMPREPLY; 511112568Smdodd phdr_len = TS_LEN; 512111765Smdodd if (!(options & F_QUIET)) 513111765Smdodd (void)printf("ICMP_TSTAMP\n"); 514112568Smdodd break; 515112568Smdodd default: 516112568Smdodd errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive."); 517112568Smdodd break; 518111765Smdodd } 519117549Smaxim icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len; 520109734Smaxim if (options & F_RROUTE) 521117548Smaxim icmp_len += MAX_IPOPTLEN; 522117548Smaxim maxpayload = IP_MAXPACKET - icmp_len; 523109734Smaxim if (datalen > maxpayload) 524112531Sbde errx(EX_USAGE, "packet size too large: %d > %d", datalen, 525109734Smaxim maxpayload); 526117548Smaxim send_len = icmp_len + datalen; 527117549Smaxim datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN]; 528110054Smdodd if (options & F_PINGFILLED) { 529110054Smdodd fill((char *)datap, payload); 530110054Smdodd } 53142337Simp if (source) { 532111932Sseanc bzero((char *)&sock_in, sizeof(sock_in)); 533111932Sseanc sock_in.sin_family = AF_INET; 534111932Sseanc if (inet_aton(source, &sock_in.sin_addr) != 0) { 53542337Simp shostname = source; 53642337Simp } else { 53742337Simp hp = gethostbyname2(source, AF_INET); 53842337Simp if (!hp) 53942337Simp errx(EX_NOHOST, "cannot resolve %s: %s", 54093638Smaxim source, hstrerror(h_errno)); 54142337Simp 542111932Sseanc sock_in.sin_len = sizeof sock_in; 543111932Sseanc if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) || 54499447Smaxim hp->h_length < 0) 54593638Smaxim errx(1, "gethostbyname2: illegal address"); 546111932Sseanc memcpy(&sock_in.sin_addr, hp->h_addr_list[0], 547111932Sseanc sizeof(sock_in.sin_addr)); 54893638Smaxim (void)strncpy(snamebuf, hp->h_name, 54993638Smaxim sizeof(snamebuf) - 1); 55042337Simp snamebuf[sizeof(snamebuf) - 1] = '\0'; 55142337Simp shostname = snamebuf; 55242337Simp } 553111932Sseanc if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1) 55442337Simp err(1, "bind"); 55542337Simp } 55642337Simp 55779403Smjacob bzero(&whereto, sizeof(whereto)); 55879403Smjacob to = &whereto; 5591558Srgrimes to->sin_family = AF_INET; 56079403Smjacob to->sin_len = sizeof *to; 56123247Swollman if (inet_aton(target, &to->sin_addr) != 0) { 5621558Srgrimes hostname = target; 56323247Swollman } else { 56423247Swollman hp = gethostbyname2(target, AF_INET); 56523247Swollman if (!hp) 56623247Swollman errx(EX_NOHOST, "cannot resolve %s: %s", 56793638Smaxim target, hstrerror(h_errno)); 56823247Swollman 569111932Sseanc if ((unsigned)hp->h_length > sizeof(to->sin_addr)) 57093638Smaxim errx(1, "gethostbyname2 returned an illegal address"); 57123247Swollman memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr); 5721558Srgrimes (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 57331956Simp hnamebuf[sizeof(hnamebuf) - 1] = '\0'; 5741558Srgrimes hostname = hnamebuf; 5751558Srgrimes } 5761558Srgrimes 57723247Swollman if (options & F_FLOOD && options & F_INTERVAL) 57823247Swollman errx(EX_USAGE, "-f and -i: incompatible options"); 5791558Srgrimes 58023247Swollman if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 58193638Smaxim errx(EX_USAGE, 58293638Smaxim "-f flag cannot be used with multicast destination"); 58323247Swollman if (options & (F_MIF | F_NOLOOP | F_MTTL) 58423247Swollman && !IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 58593638Smaxim errx(EX_USAGE, 58693638Smaxim "-I, -L, -T flags cannot be used with unicast destination"); 58723247Swollman 588112568Smdodd if (datalen >= TIMEVAL_LEN) /* can we time transfer */ 5891558Srgrimes timing = 1; 59023247Swollman 5911558Srgrimes if (!(options & F_PINGFILLED)) 592112568Smdodd for (i = TIMEVAL_LEN; i < datalen; ++i) 5931558Srgrimes *datap++ = i; 5941558Srgrimes 5951558Srgrimes ident = getpid() & 0xFFFF; 5961558Srgrimes 59717474Sfenner if (s < 0) { 59817474Sfenner errno = sockerrno; 59923247Swollman err(EX_OSERR, "socket"); 6001558Srgrimes } 6011558Srgrimes hold = 1; 6021558Srgrimes if (options & F_SO_DEBUG) 6031558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 6041558Srgrimes sizeof(hold)); 6051558Srgrimes if (options & F_SO_DONTROUTE) 6061558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 6071558Srgrimes sizeof(hold)); 60855505Sshin#ifdef IPSEC 60955505Sshin#ifdef IPSEC_POLICY_IPSEC 61055505Sshin if (options & F_POLICY) { 61155505Sshin char *buf; 61255505Sshin if (policy_in != NULL) { 61355505Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 61455505Sshin if (buf == NULL) 61568905Skris errx(EX_CONFIG, "%s", ipsec_strerror()); 61655505Sshin if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, 61755505Sshin buf, ipsec_get_policylen(buf)) < 0) 61893638Smaxim err(EX_CONFIG, 61993638Smaxim "ipsec policy cannot be configured"); 62055505Sshin free(buf); 62155505Sshin } 6221558Srgrimes 62355505Sshin if (policy_out != NULL) { 62455505Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 62555505Sshin if (buf == NULL) 62668905Skris errx(EX_CONFIG, "%s", ipsec_strerror()); 62755505Sshin if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, 62855505Sshin buf, ipsec_get_policylen(buf)) < 0) 62993638Smaxim err(EX_CONFIG, 63093638Smaxim "ipsec policy cannot be configured"); 63155505Sshin free(buf); 63255505Sshin } 63355505Sshin } 63455505Sshin#endif /*IPSEC_POLICY_IPSEC*/ 63555505Sshin#endif /*IPSEC*/ 63655505Sshin 637109731Smaxim if (options & F_HDRINCL) { 638109731Smaxim ip = (struct ip*)outpackhdr; 639109731Smaxim if (!(options & (F_TTL | F_MTTL))) { 640109731Smaxim mib[0] = CTL_NET; 641109731Smaxim mib[1] = PF_INET; 642109731Smaxim mib[2] = IPPROTO_IP; 643109731Smaxim mib[3] = IPCTL_DEFTTL; 644109731Smaxim sz = sizeof(ttl); 645109731Smaxim if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) 646109731Smaxim err(1, "sysctl(net.inet.ip.ttl)"); 647109731Smaxim } 648109731Smaxim setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); 649109731Smaxim ip->ip_v = IPVERSION; 650109731Smaxim ip->ip_hl = sizeof(struct ip) >> 2; 651109731Smaxim ip->ip_tos = tos; 652109731Smaxim ip->ip_id = 0; 653109731Smaxim ip->ip_off = df ? IP_DF : 0; 654109731Smaxim ip->ip_ttl = ttl; 655109731Smaxim ip->ip_p = IPPROTO_ICMP; 656111932Sseanc ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; 657109731Smaxim ip->ip_dst = to->sin_addr; 658109731Smaxim } 6591558Srgrimes /* record route option */ 6601558Srgrimes if (options & F_RROUTE) { 6611558Srgrimes#ifdef IP_OPTIONS 66236378Sfenner bzero(rspace, sizeof(rspace)); 6631558Srgrimes rspace[IPOPT_OPTVAL] = IPOPT_RR; 66436378Sfenner rspace[IPOPT_OLEN] = sizeof(rspace) - 1; 6651558Srgrimes rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 66636378Sfenner rspace[sizeof(rspace) - 1] = IPOPT_EOL; 6671558Srgrimes if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, 66823247Swollman sizeof(rspace)) < 0) 66923247Swollman err(EX_OSERR, "setsockopt IP_OPTIONS"); 6701558Srgrimes#else 67123247Swollman errx(EX_UNAVAILABLE, 67293638Smaxim "record route not available in this implementation"); 6731558Srgrimes#endif /* IP_OPTIONS */ 6741558Srgrimes } 6751558Srgrimes 67674029Sru if (options & F_TTL) { 67774029Sru if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, 67874029Sru sizeof(ttl)) < 0) { 67974029Sru err(EX_OSERR, "setsockopt IP_TTL"); 68074029Sru } 68174029Sru } 68220540Sfenner if (options & F_NOLOOP) { 68320540Sfenner if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, 68420540Sfenner sizeof(loop)) < 0) { 68523247Swollman err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); 68620540Sfenner } 68720540Sfenner } 68820540Sfenner if (options & F_MTTL) { 68974029Sru if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, 69074029Sru sizeof(mttl)) < 0) { 69123247Swollman err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); 69220540Sfenner } 69320540Sfenner } 69420540Sfenner if (options & F_MIF) { 69520540Sfenner if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, 69620540Sfenner sizeof(ifaddr)) < 0) { 69723247Swollman err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); 69820540Sfenner } 69920540Sfenner } 70036378Sfenner#ifdef SO_TIMESTAMP 70136378Sfenner { int on = 1; 70236378Sfenner if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) 70336378Sfenner err(EX_OSERR, "setsockopt SO_TIMESTAMP"); 70436378Sfenner } 70536378Sfenner#endif 706149086Sglebius if (sweepmax) { 707149086Sglebius if (sweepmin >= sweepmax) 708149086Sglebius errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size"); 70920540Sfenner 710149086Sglebius if (datalen != DEFDATALEN) 711149086Sglebius errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive"); 712149086Sglebius 713149086Sglebius if (npackets > 0) { 714149086Sglebius snpackets = npackets; 715149086Sglebius npackets = 0; 716149086Sglebius } else 717149086Sglebius snpackets = 1; 718149086Sglebius datalen = sweepmin; 719149086Sglebius send_len = icmp_len + sweepmin; 720149086Sglebius } 721149086Sglebius if (options & F_SWEEP && !sweepmax) 722149086Sglebius errx(EX_USAGE, "Maximum sweep size must be specified"); 723149086Sglebius 7241558Srgrimes /* 7251558Srgrimes * When pinging the broadcast address, you can get a lot of answers. 7261558Srgrimes * Doing something so evil is useful if you are trying to stress the 7271558Srgrimes * ethernet, or just want to fill the arp cache to get some stuff for 72823247Swollman * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast 72923247Swollman * or multicast pings if they wish. 7301558Srgrimes */ 73199447Smaxim 73299447Smaxim /* 73399447Smaxim * XXX receive buffer needs undetermined space for mbuf overhead 73499447Smaxim * as well. 73599447Smaxim */ 73699447Smaxim hold = IP_MAXPACKET + 128; 7371558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 7381558Srgrimes sizeof(hold)); 739109733Smaxim if (uid == 0) 74079018Srwatson (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold, 74179018Srwatson sizeof(hold)); 74279018Srwatson 74342337Simp if (to->sin_family == AF_INET) { 74442337Simp (void)printf("PING %s (%s)", hostname, 74542337Simp inet_ntoa(to->sin_addr)); 74642337Simp if (source) 74742337Simp (void)printf(" from %s", shostname); 748149086Sglebius if (sweepmax) 749149086Sglebius (void)printf(": (%d ... %d) data bytes\n", 750149086Sglebius sweepmin, sweepmax); 751149086Sglebius else 752149086Sglebius (void)printf(": %d data bytes\n", datalen); 753149086Sglebius 754149086Sglebius } else { 755149086Sglebius if (sweepmax) 756149086Sglebius (void)printf("PING %s: (%d ... %d) data bytes\n", 757149086Sglebius hostname, sweepmin, sweepmax); 758149086Sglebius else 759149086Sglebius (void)printf("PING %s: %d data bytes\n", hostname, datalen); 760149086Sglebius } 7611558Srgrimes 76220280Sbde /* 76327354Ssef * Use sigaction() instead of signal() to get unambiguous semantics, 76427354Ssef * in particular with SA_RESTART not set. 76520280Sbde */ 76627354Ssef 76720205Spst sigemptyset(&si_sa.sa_mask); 76820195Ssef si_sa.sa_flags = 0; 76927354Ssef 77027354Ssef si_sa.sa_handler = stopit; 77127354Ssef if (sigaction(SIGINT, &si_sa, 0) == -1) { 77227354Ssef err(EX_OSERR, "sigaction SIGINT"); 77327354Ssef } 77427354Ssef 77527354Ssef si_sa.sa_handler = status; 77620195Ssef if (sigaction(SIGINFO, &si_sa, 0) == -1) { 77723385Simp err(EX_OSERR, "sigaction"); 77820195Ssef } 77920195Ssef 78056342Sbillf if (alarmtimeout > 0) { 78156342Sbillf si_sa.sa_handler = stopit; 78256342Sbillf if (sigaction(SIGALRM, &si_sa, 0) == -1) 78356342Sbillf err(EX_OSERR, "sigaction SIGALRM"); 78456342Sbillf } 78556342Sbillf 78636378Sfenner bzero(&msg, sizeof(msg)); 78736378Sfenner msg.msg_name = (caddr_t)&from; 78836378Sfenner msg.msg_iov = &iov; 78936378Sfenner msg.msg_iovlen = 1; 79036378Sfenner#ifdef SO_TIMESTAMP 79136378Sfenner msg.msg_control = (caddr_t)ctrl; 79236378Sfenner#endif 79336378Sfenner iov.iov_base = packet; 794117548Smaxim iov.iov_len = IP_MAXPACKET; 79536378Sfenner 79689349Sru if (preload == 0) 79789349Sru pinger(); /* send the first ping */ 79889349Sru else { 79989349Sru if (npackets != 0 && preload > npackets) 80089349Sru preload = npackets; 80189349Sru while (preload--) /* fire off them quickies */ 80289349Sru pinger(); 80389349Sru } 80489349Sru (void)gettimeofday(&last, NULL); 8051558Srgrimes 80636378Sfenner if (options & F_FLOOD) { 80736378Sfenner intvl.tv_sec = 0; 80836378Sfenner intvl.tv_usec = 10000; 80936378Sfenner } else { 81038549Sdillon intvl.tv_sec = interval / 1000; 81138549Sdillon intvl.tv_usec = interval % 1000 * 1000; 81236378Sfenner } 8131558Srgrimes 814109733Smaxim almost_done = 0; 81527533Sbde while (!finish_up) { 816109733Smaxim struct timeval now, timeout; 81736378Sfenner fd_set rfds; 818109733Smaxim int cc, n; 8191558Srgrimes 82020280Sbde check_status(); 821111932Sseanc if ((unsigned)s >= FD_SETSIZE) 822103146Snectar errx(EX_OSERR, "descriptor too large"); 82336378Sfenner FD_ZERO(&rfds); 82436378Sfenner FD_SET(s, &rfds); 82536378Sfenner (void)gettimeofday(&now, NULL); 82636378Sfenner timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; 82736378Sfenner timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; 82836378Sfenner while (timeout.tv_usec < 0) { 82936378Sfenner timeout.tv_usec += 1000000; 83036378Sfenner timeout.tv_sec--; 8311558Srgrimes } 83237671Scharnier while (timeout.tv_usec >= 1000000) { 83336378Sfenner timeout.tv_usec -= 1000000; 83436378Sfenner timeout.tv_sec++; 83536378Sfenner } 83636378Sfenner if (timeout.tv_sec < 0) 83736378Sfenner timeout.tv_sec = timeout.tv_usec = 0; 83836378Sfenner n = select(s + 1, &rfds, NULL, NULL, &timeout); 83946643Smckay if (n < 0) 84046643Smckay continue; /* Must be EINTR. */ 84136378Sfenner if (n == 1) { 842111932Sseanc struct timeval *tv = NULL; 84336378Sfenner#ifdef SO_TIMESTAMP 84436378Sfenner struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; 84536378Sfenner 84636378Sfenner msg.msg_controllen = sizeof(ctrl); 84736378Sfenner#endif 84836378Sfenner msg.msg_namelen = sizeof(from); 84936378Sfenner if ((cc = recvmsg(s, &msg, 0)) < 0) { 85036378Sfenner if (errno == EINTR) 85136378Sfenner continue; 85237671Scharnier warn("recvmsg"); 8531558Srgrimes continue; 85436378Sfenner } 85536378Sfenner#ifdef SO_TIMESTAMP 85636378Sfenner if (cmsg->cmsg_level == SOL_SOCKET && 85736378Sfenner cmsg->cmsg_type == SCM_TIMESTAMP && 858111932Sseanc cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) { 85936713Sjb /* Copy to avoid alignment problems: */ 860103229Speter memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); 861111932Sseanc tv = &now; 86236713Sjb } 86336378Sfenner#endif 864111932Sseanc if (tv == NULL) { 86536378Sfenner (void)gettimeofday(&now, NULL); 866111932Sseanc tv = &now; 86736378Sfenner } 868111932Sseanc pr_pack((char *)packet, cc, &from, tv); 869111932Sseanc if ((options & F_ONCE && nreceived) || 870111932Sseanc (npackets && nreceived >= npackets)) 87136378Sfenner break; 8721558Srgrimes } 87346643Smckay if (n == 0 || options & F_FLOOD) { 874149086Sglebius if (sweepmax && sntransmitted == snpackets) { 875149086Sglebius for (i = 0; i < sweepincr ; ++i) 876149086Sglebius *datap++ = i; 877149086Sglebius datalen += sweepincr; 878149086Sglebius if (datalen > sweepmax) 879149086Sglebius break; 880149086Sglebius send_len = icmp_len + datalen; 881149086Sglebius sntransmitted = 0; 882149086Sglebius } 88336378Sfenner if (!npackets || ntransmitted < npackets) 88436378Sfenner pinger(); 88536378Sfenner else { 88636378Sfenner if (almost_done) 88736378Sfenner break; 88836378Sfenner almost_done = 1; 88946643Smckay intvl.tv_usec = 0; 89036378Sfenner if (nreceived) { 89136378Sfenner intvl.tv_sec = 2 * tmax / 1000; 89236378Sfenner if (!intvl.tv_sec) 89336378Sfenner intvl.tv_sec = 1; 894157535Sglebius } else { 895157535Sglebius intvl.tv_sec = waittime / 1000; 896157535Sglebius intvl.tv_usec = waittime % 1000 * 1000; 897157535Sglebius } 89836378Sfenner } 89936378Sfenner (void)gettimeofday(&last, NULL); 90083940Siedowse if (ntransmitted - nreceived - 1 > nmissedmax) { 90183940Siedowse nmissedmax = ntransmitted - nreceived - 1; 90283940Siedowse if (options & F_MISSED) 90383940Siedowse (void)write(STDOUT_FILENO, &BBELL, 1); 90483940Siedowse } 90536378Sfenner } 9061558Srgrimes } 90727533Sbde finish(); 9081558Srgrimes /* NOTREACHED */ 90923251Simp exit(0); /* Make the compiler happy */ 9101558Srgrimes} 9111558Srgrimes 9121558Srgrimes/* 91327533Sbde * stopit -- 91427533Sbde * Set the global bit that causes the main loop to quit. 91527533Sbde * Do NOT call finish() from here, since finish() does far too much 91627533Sbde * to be called from a signal handler. 91727299Sjulian */ 91827299Sjulianvoid 91927533Sbdestopit(sig) 92093643Smaxim int sig __unused; 92127299Sjulian{ 92293035Sobrien 923125605Siedowse /* 924125605Siedowse * When doing reverse DNS lookups, the finish_up flag might not 925125605Siedowse * be noticed for a while. Just exit if we get a second SIGINT. 926125605Siedowse */ 927125605Siedowse if (!(options & F_NUMERIC) && finish_up) 928125605Siedowse _exit(nreceived ? 0 : 2); 92927299Sjulian finish_up = 1; 93027299Sjulian} 93127299Sjulian 93227299Sjulian/* 9331558Srgrimes * pinger -- 9341558Srgrimes * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 9351558Srgrimes * will be added on by the kernel. The ID field is our UNIX process ID, 936111765Smdodd * and the sequence number is an ascending integer. The first TIMEVAL_LEN 93799447Smaxim * bytes of the data portion are used to hold a UNIX "timeval" struct in 93899447Smaxim * host byte-order, to compute the round-trip time. 9391558Srgrimes */ 94023247Swollmanstatic void 94123247Swollmanpinger(void) 9421558Srgrimes{ 943111765Smdodd struct timeval now; 944135957Smaxim struct tv32 tv32; 945109731Smaxim struct ip *ip; 94692806Sobrien struct icmp *icp; 94793035Sobrien int cc, i; 948109731Smaxim u_char *packet; 9491558Srgrimes 950109731Smaxim packet = outpack; 9511558Srgrimes icp = (struct icmp *)outpack; 952111765Smdodd icp->icmp_type = icmp_type; 9531558Srgrimes icp->icmp_code = 0; 9541558Srgrimes icp->icmp_cksum = 0; 95591432Sfenner icp->icmp_seq = htons(ntransmitted); 9561558Srgrimes icp->icmp_id = ident; /* ID */ 9571558Srgrimes 95891432Sfenner CLR(ntransmitted % mx_dup_ck); 9591558Srgrimes 960111765Smdodd if ((options & F_TIME) || timing) { 961111765Smdodd (void)gettimeofday(&now, NULL); 9621558Srgrimes 963135957Smaxim tv32.tv32_sec = htonl(now.tv_sec); 964135957Smaxim tv32.tv32_usec = htonl(now.tv_usec); 965111765Smdodd if (options & F_TIME) 966111765Smdodd icp->icmp_otime = htonl((now.tv_sec % (24*60*60)) 967111765Smdodd * 1000 + now.tv_usec / 1000); 968111765Smdodd if (timing) 969135957Smaxim bcopy((void *)&tv32, 970117549Smaxim (void *)&outpack[ICMP_MINLEN + phdr_len], 971135957Smaxim sizeof(tv32)); 972111765Smdodd } 9731558Srgrimes 974117549Smaxim cc = ICMP_MINLEN + phdr_len + datalen; 975111765Smdodd 9761558Srgrimes /* compute ICMP checksum here */ 9771558Srgrimes icp->icmp_cksum = in_cksum((u_short *)icp, cc); 9781558Srgrimes 979109731Smaxim if (options & F_HDRINCL) { 980109731Smaxim cc += sizeof(struct ip); 981109731Smaxim ip = (struct ip *)outpackhdr; 982109731Smaxim ip->ip_len = cc; 983109731Smaxim ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); 984109731Smaxim packet = outpackhdr; 985109731Smaxim } 986109731Smaxim i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto, 98779403Smjacob sizeof(whereto)); 9881558Srgrimes 9891558Srgrimes if (i < 0 || i != cc) { 99023247Swollman if (i < 0) { 99127533Sbde if (options & F_FLOOD && errno == ENOBUFS) { 99227299Sjulian usleep(FLOOD_BACKOFF); 99327299Sjulian return; 99427299Sjulian } 99523247Swollman warn("sendto"); 99623247Swollman } else { 99723247Swollman warn("%s: partial write: %d of %d bytes", 99835216Sphk hostname, i, cc); 99923247Swollman } 100027945Sjulian } 100127945Sjulian ntransmitted++; 1002149086Sglebius sntransmitted++; 10031558Srgrimes if (!(options & F_QUIET) && options & F_FLOOD) 10041558Srgrimes (void)write(STDOUT_FILENO, &DOT, 1); 10051558Srgrimes} 10061558Srgrimes 10071558Srgrimes/* 10081558Srgrimes * pr_pack -- 10091558Srgrimes * Print out the packet, if it came from us. This logic is necessary 10101558Srgrimes * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 10111558Srgrimes * which arrive ('tis only fair). This permits multiple copies of this 10121558Srgrimes * program to be run without having intermingled output (or statistics!). 10131558Srgrimes */ 101423247Swollmanstatic void 101536378Sfennerpr_pack(buf, cc, from, tv) 10161558Srgrimes char *buf; 10171558Srgrimes int cc; 10181558Srgrimes struct sockaddr_in *from; 101936378Sfenner struct timeval *tv; 10201558Srgrimes{ 1021103229Speter struct in_addr ina; 1022103229Speter u_char *cp, *dp; 102392806Sobrien struct icmp *icp; 102493035Sobrien struct ip *ip; 1025103227Speter const void *tp; 102693035Sobrien double triptime; 1027117548Smaxim int dupflag, hlen, i, j, recv_len, seq; 10281558Srgrimes static int old_rrlen; 10291558Srgrimes static char old_rr[MAX_IPOPTLEN]; 10301558Srgrimes 10311558Srgrimes /* Check the IP header */ 10321558Srgrimes ip = (struct ip *)buf; 10331558Srgrimes hlen = ip->ip_hl << 2; 1034117548Smaxim recv_len = cc; 10351558Srgrimes if (cc < hlen + ICMP_MINLEN) { 10361558Srgrimes if (options & F_VERBOSE) 103723247Swollman warn("packet too short (%d bytes) from %s", cc, 103823247Swollman inet_ntoa(from->sin_addr)); 10391558Srgrimes return; 10401558Srgrimes } 10411558Srgrimes 10421558Srgrimes /* Now the ICMP part */ 10431558Srgrimes cc -= hlen; 10441558Srgrimes icp = (struct icmp *)(buf + hlen); 1045111765Smdodd if (icp->icmp_type == icmp_type_rsp) { 10461558Srgrimes if (icp->icmp_id != ident) 10471558Srgrimes return; /* 'Twas not our ECHO */ 10481558Srgrimes ++nreceived; 104927533Sbde triptime = 0.0; 10501558Srgrimes if (timing) { 105136089Sjb struct timeval tv1; 1052135957Smaxim struct tv32 tv32; 10531558Srgrimes#ifndef icmp_data 1054103227Speter tp = &icp->icmp_ip; 10551558Srgrimes#else 1056103227Speter tp = icp->icmp_data; 10571558Srgrimes#endif 1058133723Sstefanf tp = (const char *)tp + phdr_len; 1059110009Smdodd 1060113217Smdodd if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) { 1061113217Smdodd /* Copy to avoid alignment problems: */ 1062135957Smaxim memcpy(&tv32, tp, sizeof(tv32)); 1063135957Smaxim tv1.tv_sec = ntohl(tv32.tv32_sec); 1064135957Smaxim tv1.tv_usec = ntohl(tv32.tv32_usec); 1065113217Smdodd tvsub(tv, &tv1); 1066113217Smdodd triptime = ((double)tv->tv_sec) * 1000.0 + 1067113217Smdodd ((double)tv->tv_usec) / 1000.0; 1068113217Smdodd tsum += triptime; 1069113217Smdodd tsumsq += triptime * triptime; 1070113217Smdodd if (triptime < tmin) 1071113217Smdodd tmin = triptime; 1072113217Smdodd if (triptime > tmax) 1073113217Smdodd tmax = triptime; 1074113217Smdodd } else 1075113217Smdodd timing = 0; 10761558Srgrimes } 10771558Srgrimes 107891432Sfenner seq = ntohs(icp->icmp_seq); 107991432Sfenner 108091432Sfenner if (TST(seq % mx_dup_ck)) { 10811558Srgrimes ++nrepeats; 10821558Srgrimes --nreceived; 10831558Srgrimes dupflag = 1; 10841558Srgrimes } else { 108591432Sfenner SET(seq % mx_dup_ck); 10861558Srgrimes dupflag = 0; 10871558Srgrimes } 10881558Srgrimes 10891558Srgrimes if (options & F_QUIET) 10901558Srgrimes return; 1091157535Sglebius 1092157535Sglebius if (options & F_WAITTIME && triptime > waittime) { 1093157535Sglebius ++nrcvtimeout; 1094157535Sglebius return; 1095157535Sglebius } 10961558Srgrimes 10971558Srgrimes if (options & F_FLOOD) 10981558Srgrimes (void)write(STDOUT_FILENO, &BSPACE, 1); 10991558Srgrimes else { 11001558Srgrimes (void)printf("%d bytes from %s: icmp_seq=%u", cc, 11011558Srgrimes inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 110291432Sfenner seq); 11031558Srgrimes (void)printf(" ttl=%d", ip->ip_ttl); 11041558Srgrimes if (timing) 11051859Sdg (void)printf(" time=%.3f ms", triptime); 11061558Srgrimes if (dupflag) 11071558Srgrimes (void)printf(" (DUP!)"); 110822417Sdanny if (options & F_AUDIBLE) 110977119Sphk (void)write(STDOUT_FILENO, &BBELL, 1); 1110110009Smdodd if (options & F_MASK) { 1111110009Smdodd /* Just prentend this cast isn't ugly */ 1112110009Smdodd (void)printf(" mask=%s", 1113110009Smdodd pr_addr(*(struct in_addr *)&(icp->icmp_mask))); 1114110009Smdodd } 1115111765Smdodd if (options & F_TIME) { 1116111765Smdodd (void)printf(" tso=%s", pr_ntime(icp->icmp_otime)); 1117111765Smdodd (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime)); 1118111765Smdodd (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime)); 1119111765Smdodd } 1120117548Smaxim if (recv_len != send_len) { 1121117548Smaxim (void)printf( 1122117548Smaxim "\nwrong total length %d instead of %d", 1123117548Smaxim recv_len, send_len); 1124117548Smaxim } 11251558Srgrimes /* check the data */ 1126111765Smdodd cp = (u_char*)&icp->icmp_data[phdr_len]; 1127117549Smaxim dp = &outpack[ICMP_MINLEN + phdr_len]; 1128113217Smdodd cc -= ICMP_MINLEN + phdr_len; 1129113463Smaxim i = 0; 1130113463Smaxim if (timing) { /* don't check variable timestamp */ 1131113463Smaxim cp += TIMEVAL_LEN; 1132113463Smaxim dp += TIMEVAL_LEN; 1133113463Smaxim cc -= TIMEVAL_LEN; 1134113463Smaxim i += TIMEVAL_LEN; 1135113463Smaxim } 1136113463Smaxim for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) { 11371558Srgrimes if (*cp != *dp) { 11381558Srgrimes (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 11391558Srgrimes i, *dp, *cp); 114093638Smaxim (void)printf("\ncp:"); 11411558Srgrimes cp = (u_char*)&icp->icmp_data[0]; 114236089Sjb for (i = 0; i < datalen; ++i, ++cp) { 1143117548Smaxim if ((i % 16) == 8) 11441558Srgrimes (void)printf("\n\t"); 1145117548Smaxim (void)printf("%2x ", *cp); 11461558Srgrimes } 114793638Smaxim (void)printf("\ndp:"); 1148117549Smaxim cp = &outpack[ICMP_MINLEN]; 114936089Sjb for (i = 0; i < datalen; ++i, ++cp) { 1150117548Smaxim if ((i % 16) == 8) 115136089Sjb (void)printf("\n\t"); 1152117548Smaxim (void)printf("%2x ", *cp); 115336089Sjb } 11541558Srgrimes break; 11551558Srgrimes } 11561558Srgrimes } 11571558Srgrimes } 11581558Srgrimes } else { 115917724Sfenner /* 116017724Sfenner * We've got something other than an ECHOREPLY. 116117724Sfenner * See if it's a reply to something that we sent. 116217724Sfenner * We can compare IP destination, protocol, 116317724Sfenner * and ICMP type and ID. 116423251Simp * 116523251Simp * Only print all the error messages if we are running 116693638Smaxim * as root to avoid leaking information not normally 116723251Simp * available to those not running as root. 116817724Sfenner */ 116917724Sfenner#ifndef icmp_data 117017724Sfenner struct ip *oip = &icp->icmp_ip; 117117724Sfenner#else 117217724Sfenner struct ip *oip = (struct ip *)icp->icmp_data; 117317724Sfenner#endif 117417724Sfenner struct icmp *oicmp = (struct icmp *)(oip + 1); 117517724Sfenner 117623295Simp if (((options & F_VERBOSE) && uid == 0) || 117717724Sfenner (!(options & F_QUIET2) && 117879403Smjacob (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) && 117917724Sfenner (oip->ip_p == IPPROTO_ICMP) && 118017724Sfenner (oicmp->icmp_type == ICMP_ECHO) && 118117724Sfenner (oicmp->icmp_id == ident))) { 118217724Sfenner (void)printf("%d bytes from %s: ", cc, 118323247Swollman pr_addr(from->sin_addr)); 118417724Sfenner pr_icmph(icp); 118517724Sfenner } else 118617724Sfenner return; 11871558Srgrimes } 11881558Srgrimes 11891558Srgrimes /* Display any IP options */ 11901558Srgrimes cp = (u_char *)buf + sizeof(struct ip); 11911558Srgrimes 11921558Srgrimes for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 11931558Srgrimes switch (*cp) { 11941558Srgrimes case IPOPT_EOL: 11951558Srgrimes hlen = 0; 11961558Srgrimes break; 11971558Srgrimes case IPOPT_LSRR: 1198109730Smaxim case IPOPT_SSRR: 1199109730Smaxim (void)printf(*cp == IPOPT_LSRR ? 1200109730Smaxim "\nLSRR: " : "\nSSRR: "); 120199446Smaxim j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1; 12021558Srgrimes hlen -= 2; 120399446Smaxim cp += 2; 1204105624Smaxim if (j >= INADDR_LEN && 1205105624Smaxim j <= hlen - (int)sizeof(struct ip)) { 12061558Srgrimes for (;;) { 120799446Smaxim bcopy(++cp, &ina.s_addr, INADDR_LEN); 120899446Smaxim if (ina.s_addr == 0) 120993638Smaxim (void)printf("\t0.0.0.0"); 121099446Smaxim else 121193638Smaxim (void)printf("\t%s", 121293638Smaxim pr_addr(ina)); 121399446Smaxim hlen -= INADDR_LEN; 121499446Smaxim cp += INADDR_LEN - 1; 121599446Smaxim j -= INADDR_LEN; 121699446Smaxim if (j < INADDR_LEN) 121799446Smaxim break; 121899446Smaxim (void)putchar('\n'); 121999446Smaxim } 122099446Smaxim } else 122199446Smaxim (void)printf("\t(truncated route)\n"); 12221558Srgrimes break; 12231558Srgrimes case IPOPT_RR: 122499446Smaxim j = cp[IPOPT_OLEN]; /* get length */ 122599446Smaxim i = cp[IPOPT_OFFSET]; /* and pointer */ 12261558Srgrimes hlen -= 2; 122799446Smaxim cp += 2; 12281558Srgrimes if (i > j) 12291558Srgrimes i = j; 123099446Smaxim i = i - IPOPT_MINOFF + 1; 123199446Smaxim if (i < 0 || i > (hlen - (int)sizeof(struct ip))) { 123299446Smaxim old_rrlen = 0; 12331558Srgrimes continue; 123499446Smaxim } 12351558Srgrimes if (i == old_rrlen 12361558Srgrimes && !bcmp((char *)cp, old_rr, i) 12371558Srgrimes && !(options & F_FLOOD)) { 12381558Srgrimes (void)printf("\t(same route)"); 12391558Srgrimes hlen -= i; 12401558Srgrimes cp += i; 12411558Srgrimes break; 12421558Srgrimes } 124399446Smaxim old_rrlen = i; 124499446Smaxim bcopy((char *)cp, old_rr, i); 12451558Srgrimes (void)printf("\nRR: "); 124699446Smaxim if (i >= INADDR_LEN && 124799446Smaxim i <= hlen - (int)sizeof(struct ip)) { 124899446Smaxim for (;;) { 124999446Smaxim bcopy(++cp, &ina.s_addr, INADDR_LEN); 125099446Smaxim if (ina.s_addr == 0) 125199446Smaxim (void)printf("\t0.0.0.0"); 125299446Smaxim else 125399446Smaxim (void)printf("\t%s", 125499446Smaxim pr_addr(ina)); 125599446Smaxim hlen -= INADDR_LEN; 125699446Smaxim cp += INADDR_LEN - 1; 125799446Smaxim i -= INADDR_LEN; 125899446Smaxim if (i < INADDR_LEN) 125999446Smaxim break; 126099446Smaxim (void)putchar('\n'); 126123247Swollman } 126299446Smaxim } else 126399446Smaxim (void)printf("\t(truncated route)"); 12641558Srgrimes break; 12651558Srgrimes case IPOPT_NOP: 12661558Srgrimes (void)printf("\nNOP"); 12671558Srgrimes break; 12681558Srgrimes default: 12691558Srgrimes (void)printf("\nunknown option %x", *cp); 12701558Srgrimes break; 12711558Srgrimes } 12721558Srgrimes if (!(options & F_FLOOD)) { 12731558Srgrimes (void)putchar('\n'); 12741558Srgrimes (void)fflush(stdout); 12751558Srgrimes } 12761558Srgrimes} 12771558Srgrimes 12781558Srgrimes/* 12791558Srgrimes * in_cksum -- 12801558Srgrimes * Checksum routine for Internet Protocol family headers (C Version) 12811558Srgrimes */ 128223247Swollmanu_short 12831558Srgrimesin_cksum(addr, len) 12841558Srgrimes u_short *addr; 12851558Srgrimes int len; 12861558Srgrimes{ 128793035Sobrien int nleft, sum; 128893035Sobrien u_short *w; 128953191Spb union { 129053369Spb u_short us; 129153369Spb u_char uc[2]; 129253369Spb } last; 129353369Spb u_short answer; 12941558Srgrimes 129593035Sobrien nleft = len; 129693035Sobrien sum = 0; 129793035Sobrien w = addr; 129893035Sobrien 12991558Srgrimes /* 13001558Srgrimes * Our algorithm is simple, using a 32 bit accumulator (sum), we add 13011558Srgrimes * sequential 16 bit words to it, and at the end, fold back all the 13021558Srgrimes * carry bits from the top 16 bits into the lower 16 bits. 13031558Srgrimes */ 13041558Srgrimes while (nleft > 1) { 13051558Srgrimes sum += *w++; 13061558Srgrimes nleft -= 2; 13071558Srgrimes } 13081558Srgrimes 13091558Srgrimes /* mop up an odd byte, if necessary */ 13101558Srgrimes if (nleft == 1) { 131153369Spb last.uc[0] = *(u_char *)w; 131253369Spb last.uc[1] = 0; 131353369Spb sum += last.us; 13141558Srgrimes } 13151558Srgrimes 13161558Srgrimes /* add back carry outs from top 16 bits to low 16 bits */ 13171558Srgrimes sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 13181558Srgrimes sum += (sum >> 16); /* add carry */ 131953369Spb answer = ~sum; /* truncate to 16 bits */ 132053369Spb return(answer); 13211558Srgrimes} 13221558Srgrimes 13231558Srgrimes/* 13241558Srgrimes * tvsub -- 13251558Srgrimes * Subtract 2 timeval structs: out = out - in. Out is assumed to 13261558Srgrimes * be >= in. 13271558Srgrimes */ 132823247Swollmanstatic void 13291558Srgrimestvsub(out, in) 133092806Sobrien struct timeval *out, *in; 13311558Srgrimes{ 133293035Sobrien 13331558Srgrimes if ((out->tv_usec -= in->tv_usec) < 0) { 13341558Srgrimes --out->tv_sec; 13351558Srgrimes out->tv_usec += 1000000; 13361558Srgrimes } 13371558Srgrimes out->tv_sec -= in->tv_sec; 13381558Srgrimes} 13391558Srgrimes 13401558Srgrimes/* 13413792Ssef * status -- 13423792Ssef * Print out statistics when SIGINFO is received. 13433792Ssef */ 13443792Ssef 134523247Swollmanstatic void 134620280Sbdestatus(sig) 134793643Smaxim int sig __unused; 134820280Sbde{ 134993035Sobrien 135020195Ssef siginfo_p = 1; 135120195Ssef} 135220195Ssef 135323247Swollmanstatic void 135420195Ssefcheck_status() 13553792Ssef{ 135693035Sobrien 135720195Ssef if (siginfo_p) { 135820195Ssef siginfo_p = 0; 1359161273Sdd (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)", 136020280Sbde nreceived, ntransmitted, 1361115691Smaxim ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0); 1362115691Smaxim if (nreceived && timing) 1363115691Smaxim (void)fprintf(stderr, " %.3f min / %.3f avg / %.3f max", 1364115691Smaxim tmin, tsum / (nreceived + nrepeats), tmax); 1365115691Smaxim (void)fprintf(stderr, "\n"); 136620195Ssef } 13673792Ssef} 13683792Ssef 13693792Ssef/* 13701558Srgrimes * finish -- 13711558Srgrimes * Print out statistics, and give up. 13721558Srgrimes */ 137323247Swollmanstatic void 137427533Sbdefinish() 13751558Srgrimes{ 13761558Srgrimes 13771558Srgrimes (void)signal(SIGINT, SIG_IGN); 137827354Ssef (void)signal(SIGALRM, SIG_IGN); 13791558Srgrimes (void)putchar('\n'); 13801558Srgrimes (void)fflush(stdout); 13811558Srgrimes (void)printf("--- %s ping statistics ---\n", hostname); 13821558Srgrimes (void)printf("%ld packets transmitted, ", ntransmitted); 13831558Srgrimes (void)printf("%ld packets received, ", nreceived); 13841558Srgrimes if (nrepeats) 13851558Srgrimes (void)printf("+%ld duplicates, ", nrepeats); 138646080Simp if (ntransmitted) { 13871558Srgrimes if (nreceived > ntransmitted) 13881558Srgrimes (void)printf("-- somebody's printing up packets!"); 13891558Srgrimes else 1390161273Sdd (void)printf("%.1f%% packet loss", 1391161273Sdd ((ntransmitted - nreceived) * 100.0) / 1392161273Sdd ntransmitted); 139346080Simp } 1394157535Sglebius if (nrcvtimeout) 1395157535Sglebius (void)printf(", %ld packets out of wait time", nrcvtimeout); 13961558Srgrimes (void)putchar('\n'); 139727508Swollman if (nreceived && timing) { 139827508Swollman double n = nreceived + nrepeats; 139927508Swollman double avg = tsum / n; 140027508Swollman double vari = tsumsq / n - avg * avg; 140193638Smaxim (void)printf( 140293638Smaxim "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", 140327508Swollman tmin, avg, tmax, sqrt(vari)); 140427508Swollman } 14053792Ssef 14068871Srgrimes if (nreceived) 14074862Sdg exit(0); 14084862Sdg else 14094862Sdg exit(2); 14101558Srgrimes} 14111558Srgrimes 14121558Srgrimes#ifdef notdef 14131558Srgrimesstatic char *ttab[] = { 14141558Srgrimes "Echo Reply", /* ip + seq + udata */ 14151558Srgrimes "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 14161558Srgrimes "Source Quench", /* IP */ 14171558Srgrimes "Redirect", /* redirect type, gateway, + IP */ 14181558Srgrimes "Echo", 14191558Srgrimes "Time Exceeded", /* transit, frag reassem + IP */ 14201558Srgrimes "Parameter Problem", /* pointer + IP */ 14211558Srgrimes "Timestamp", /* id + seq + three timestamps */ 14221558Srgrimes "Timestamp Reply", /* " */ 14231558Srgrimes "Info Request", /* id + sq */ 14241558Srgrimes "Info Reply" /* " */ 14251558Srgrimes}; 14261558Srgrimes#endif 14271558Srgrimes 14281558Srgrimes/* 14291558Srgrimes * pr_icmph -- 14301558Srgrimes * Print a descriptive string about an ICMP header. 14311558Srgrimes */ 143223247Swollmanstatic void 14331558Srgrimespr_icmph(icp) 14341558Srgrimes struct icmp *icp; 14351558Srgrimes{ 143693035Sobrien 14371558Srgrimes switch(icp->icmp_type) { 14381558Srgrimes case ICMP_ECHOREPLY: 14391558Srgrimes (void)printf("Echo Reply\n"); 14401558Srgrimes /* XXX ID + Seq + Data */ 14411558Srgrimes break; 14421558Srgrimes case ICMP_UNREACH: 14431558Srgrimes switch(icp->icmp_code) { 14441558Srgrimes case ICMP_UNREACH_NET: 14451558Srgrimes (void)printf("Destination Net Unreachable\n"); 14461558Srgrimes break; 14471558Srgrimes case ICMP_UNREACH_HOST: 14481558Srgrimes (void)printf("Destination Host Unreachable\n"); 14491558Srgrimes break; 14501558Srgrimes case ICMP_UNREACH_PROTOCOL: 14511558Srgrimes (void)printf("Destination Protocol Unreachable\n"); 14521558Srgrimes break; 14531558Srgrimes case ICMP_UNREACH_PORT: 14541558Srgrimes (void)printf("Destination Port Unreachable\n"); 14551558Srgrimes break; 14561558Srgrimes case ICMP_UNREACH_NEEDFRAG: 145717724Sfenner (void)printf("frag needed and DF set (MTU %d)\n", 145828059Sfenner ntohs(icp->icmp_nextmtu)); 14591558Srgrimes break; 14601558Srgrimes case ICMP_UNREACH_SRCFAIL: 14611558Srgrimes (void)printf("Source Route Failed\n"); 14621558Srgrimes break; 146317724Sfenner case ICMP_UNREACH_FILTER_PROHIB: 146417724Sfenner (void)printf("Communication prohibited by filter\n"); 146517724Sfenner break; 14661558Srgrimes default: 14671558Srgrimes (void)printf("Dest Unreachable, Bad Code: %d\n", 14681558Srgrimes icp->icmp_code); 14691558Srgrimes break; 14701558Srgrimes } 14711558Srgrimes /* Print returned IP header information */ 14721558Srgrimes#ifndef icmp_data 14731558Srgrimes pr_retip(&icp->icmp_ip); 14741558Srgrimes#else 14751558Srgrimes pr_retip((struct ip *)icp->icmp_data); 14761558Srgrimes#endif 14771558Srgrimes break; 14781558Srgrimes case ICMP_SOURCEQUENCH: 14791558Srgrimes (void)printf("Source Quench\n"); 14801558Srgrimes#ifndef icmp_data 14811558Srgrimes pr_retip(&icp->icmp_ip); 14821558Srgrimes#else 14831558Srgrimes pr_retip((struct ip *)icp->icmp_data); 14841558Srgrimes#endif 14851558Srgrimes break; 14861558Srgrimes case ICMP_REDIRECT: 14871558Srgrimes switch(icp->icmp_code) { 14881558Srgrimes case ICMP_REDIRECT_NET: 14891558Srgrimes (void)printf("Redirect Network"); 14901558Srgrimes break; 14911558Srgrimes case ICMP_REDIRECT_HOST: 14921558Srgrimes (void)printf("Redirect Host"); 14931558Srgrimes break; 14941558Srgrimes case ICMP_REDIRECT_TOSNET: 14951558Srgrimes (void)printf("Redirect Type of Service and Network"); 14961558Srgrimes break; 14971558Srgrimes case ICMP_REDIRECT_TOSHOST: 14981558Srgrimes (void)printf("Redirect Type of Service and Host"); 14991558Srgrimes break; 15001558Srgrimes default: 15011558Srgrimes (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 15021558Srgrimes break; 15031558Srgrimes } 150428059Sfenner (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); 15051558Srgrimes#ifndef icmp_data 15061558Srgrimes pr_retip(&icp->icmp_ip); 15071558Srgrimes#else 15081558Srgrimes pr_retip((struct ip *)icp->icmp_data); 15091558Srgrimes#endif 15101558Srgrimes break; 15111558Srgrimes case ICMP_ECHO: 15121558Srgrimes (void)printf("Echo Request\n"); 15131558Srgrimes /* XXX ID + Seq + Data */ 15141558Srgrimes break; 15151558Srgrimes case ICMP_TIMXCEED: 15161558Srgrimes switch(icp->icmp_code) { 15171558Srgrimes case ICMP_TIMXCEED_INTRANS: 15181558Srgrimes (void)printf("Time to live exceeded\n"); 15191558Srgrimes break; 15201558Srgrimes case ICMP_TIMXCEED_REASS: 15211558Srgrimes (void)printf("Frag reassembly time exceeded\n"); 15221558Srgrimes break; 15231558Srgrimes default: 15241558Srgrimes (void)printf("Time exceeded, Bad Code: %d\n", 15251558Srgrimes icp->icmp_code); 15261558Srgrimes break; 15271558Srgrimes } 15281558Srgrimes#ifndef icmp_data 15291558Srgrimes pr_retip(&icp->icmp_ip); 15301558Srgrimes#else 15311558Srgrimes pr_retip((struct ip *)icp->icmp_data); 15321558Srgrimes#endif 15331558Srgrimes break; 15341558Srgrimes case ICMP_PARAMPROB: 15351558Srgrimes (void)printf("Parameter problem: pointer = 0x%02x\n", 15361558Srgrimes icp->icmp_hun.ih_pptr); 15371558Srgrimes#ifndef icmp_data 15381558Srgrimes pr_retip(&icp->icmp_ip); 15391558Srgrimes#else 15401558Srgrimes pr_retip((struct ip *)icp->icmp_data); 15411558Srgrimes#endif 15421558Srgrimes break; 15431558Srgrimes case ICMP_TSTAMP: 15441558Srgrimes (void)printf("Timestamp\n"); 15451558Srgrimes /* XXX ID + Seq + 3 timestamps */ 15461558Srgrimes break; 15471558Srgrimes case ICMP_TSTAMPREPLY: 15481558Srgrimes (void)printf("Timestamp Reply\n"); 15491558Srgrimes /* XXX ID + Seq + 3 timestamps */ 15501558Srgrimes break; 15511558Srgrimes case ICMP_IREQ: 15521558Srgrimes (void)printf("Information Request\n"); 15531558Srgrimes /* XXX ID + Seq */ 15541558Srgrimes break; 15551558Srgrimes case ICMP_IREQREPLY: 15561558Srgrimes (void)printf("Information Reply\n"); 15571558Srgrimes /* XXX ID + Seq */ 15581558Srgrimes break; 15591558Srgrimes case ICMP_MASKREQ: 15601558Srgrimes (void)printf("Address Mask Request\n"); 15611558Srgrimes break; 15621558Srgrimes case ICMP_MASKREPLY: 15631558Srgrimes (void)printf("Address Mask Reply\n"); 15641558Srgrimes break; 156517724Sfenner case ICMP_ROUTERADVERT: 156617724Sfenner (void)printf("Router Advertisement\n"); 156717724Sfenner break; 156817724Sfenner case ICMP_ROUTERSOLICIT: 156917724Sfenner (void)printf("Router Solicitation\n"); 157017724Sfenner break; 15711558Srgrimes default: 15721558Srgrimes (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 15731558Srgrimes } 15741558Srgrimes} 15751558Srgrimes 15761558Srgrimes/* 15771558Srgrimes * pr_iph -- 15781558Srgrimes * Print an IP header with options. 15791558Srgrimes */ 158023247Swollmanstatic void 15811558Srgrimespr_iph(ip) 15821558Srgrimes struct ip *ip; 15831558Srgrimes{ 158493035Sobrien u_char *cp; 15851558Srgrimes int hlen; 15861558Srgrimes 15871558Srgrimes hlen = ip->ip_hl << 2; 15881558Srgrimes cp = (u_char *)ip + 20; /* point to options */ 15891558Srgrimes 159017724Sfenner (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); 15911558Srgrimes (void)printf(" %1x %1x %02x %04x %04x", 159217724Sfenner ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 159317724Sfenner ntohs(ip->ip_id)); 159436089Sjb (void)printf(" %1lx %04lx", 159536089Sjb (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13, 159636089Sjb (u_long) ntohl(ip->ip_off) & 0x1fff); 159717724Sfenner (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 159817724Sfenner ntohs(ip->ip_sum)); 15991558Srgrimes (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); 16001558Srgrimes (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); 160117724Sfenner /* dump any option bytes */ 16021558Srgrimes while (hlen-- > 20) { 16031558Srgrimes (void)printf("%02x", *cp++); 16041558Srgrimes } 16051558Srgrimes (void)putchar('\n'); 16061558Srgrimes} 16071558Srgrimes 16081558Srgrimes/* 16091558Srgrimes * pr_addr -- 16101558Srgrimes * Return an ascii host address as a dotted quad and optionally with 16111558Srgrimes * a hostname. 16121558Srgrimes */ 161323247Swollmanstatic char * 161423247Swollmanpr_addr(ina) 161523247Swollman struct in_addr ina; 16161558Srgrimes{ 16171558Srgrimes struct hostent *hp; 161823251Simp static char buf[16 + 3 + MAXHOSTNAMELEN]; 16191558Srgrimes 16201558Srgrimes if ((options & F_NUMERIC) || 162123247Swollman !(hp = gethostbyaddr((char *)&ina, 4, AF_INET))) 162223247Swollman return inet_ntoa(ina); 16231558Srgrimes else 162417320Speter (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 162523247Swollman inet_ntoa(ina)); 16261558Srgrimes return(buf); 16271558Srgrimes} 16281558Srgrimes 16291558Srgrimes/* 16301558Srgrimes * pr_retip -- 16311558Srgrimes * Dump some info on a returned (via ICMP) IP packet. 16321558Srgrimes */ 163323247Swollmanstatic void 16341558Srgrimespr_retip(ip) 16351558Srgrimes struct ip *ip; 16361558Srgrimes{ 163793035Sobrien u_char *cp; 16381558Srgrimes int hlen; 16391558Srgrimes 16401558Srgrimes pr_iph(ip); 16411558Srgrimes hlen = ip->ip_hl << 2; 16421558Srgrimes cp = (u_char *)ip + hlen; 16431558Srgrimes 16441558Srgrimes if (ip->ip_p == 6) 16451558Srgrimes (void)printf("TCP: from port %u, to port %u (decimal)\n", 16461558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 16471558Srgrimes else if (ip->ip_p == 17) 16481558Srgrimes (void)printf("UDP: from port %u, to port %u (decimal)\n", 16491558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 16501558Srgrimes} 16511558Srgrimes 1652111765Smdoddstatic char * 1653117550Smaximpr_ntime (n_time timestamp) 1654111765Smdodd{ 1655111765Smdodd static char buf[10]; 1656117550Smaxim int hour, min, sec; 1657111765Smdodd 1658117550Smaxim sec = ntohl(timestamp) / 1000; 1659117550Smaxim hour = sec / 60 / 60; 1660117550Smaxim min = (sec % (60 * 60)) / 60; 1661117550Smaxim sec = (sec % (60 * 60)) % 60; 1662111765Smdodd 1663117550Smaxim (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec); 1664111765Smdodd 1665111765Smdodd return (buf); 1666111765Smdodd} 1667111765Smdodd 166823247Swollmanstatic void 16691558Srgrimesfill(bp, patp) 16701558Srgrimes char *bp, *patp; 16711558Srgrimes{ 167293035Sobrien char *cp; 167393035Sobrien int pat[16]; 167499447Smaxim u_int ii, jj, kk; 16751558Srgrimes 167623247Swollman for (cp = patp; *cp; cp++) { 167723247Swollman if (!isxdigit(*cp)) 167893638Smaxim errx(EX_USAGE, 167993638Smaxim "patterns must be specified as hex digits"); 168093638Smaxim 168123247Swollman } 16821558Srgrimes ii = sscanf(patp, 16831558Srgrimes "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 16841558Srgrimes &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 16851558Srgrimes &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 16861558Srgrimes &pat[13], &pat[14], &pat[15]); 16871558Srgrimes 16881558Srgrimes if (ii > 0) 1689112568Smdodd for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii) 16901558Srgrimes for (jj = 0; jj < ii; ++jj) 16911558Srgrimes bp[jj + kk] = pat[jj]; 16921558Srgrimes if (!(options & F_QUIET)) { 16931558Srgrimes (void)printf("PATTERN: 0x"); 16941558Srgrimes for (jj = 0; jj < ii; ++jj) 16951558Srgrimes (void)printf("%02x", bp[jj] & 0xFF); 16961558Srgrimes (void)printf("\n"); 16971558Srgrimes } 16981558Srgrimes} 16991558Srgrimes 1700112228Sru#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 1701112228Sru#define SECOPT " [-P policy]" 1702112228Sru#else 1703112228Sru#define SECOPT "" 1704112228Sru#endif 170523247Swollmanstatic void 170637671Scharnierusage() 17071558Srgrimes{ 1708112228Sru 1709157535Sglebius (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 1710152996Sru"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]", 1711152996Sru" [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]", 1712152996Sru" " SECOPT " [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]", 1713157535Sglebius" [-W waittime] [-z tos] host", 1714112110Sru" ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]", 1715112228Sru" [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]", 1716157535Sglebius" [-s packetsize] [-T ttl] [-t timeout] [-W waittime]", 1717157535Sglebius" [-z tos] mcast-group"); 171823247Swollman exit(EX_USAGE); 17191558Srgrimes} 1720