ping.c revision 102471
1251881Speter/* 2251881Speter * Copyright (c) 1989, 1993 3251881Speter * The Regents of the University of California. All rights reserved. 4251881Speter * 5251881Speter * This code is derived from software contributed to Berkeley by 6251881Speter * Mike Muuss. 7251881Speter * 8251881Speter * Redistribution and use in source and binary forms, with or without 9251881Speter * modification, are permitted provided that the following conditions 10251881Speter * are met: 11251881Speter * 1. Redistributions of source code must retain the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer. 13251881Speter * 2. Redistributions in binary form must reproduce the above copyright 14251881Speter * notice, this list of conditions and the following disclaimer in the 15251881Speter * documentation and/or other materials provided with the distribution. 16251881Speter * 3. All advertising materials mentioning features or use of this software 17251881Speter * must display the following acknowledgement: 18251881Speter * This product includes software developed by the University of 19251881Speter * California, Berkeley and its contributors. 20251881Speter * 4. Neither the name of the University nor the names of its contributors 21251881Speter * may be used to endorse or promote products derived from this software 22251881Speter * without specific prior written permission. 23251881Speter * 24251881Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34251881Speter * SUCH DAMAGE. 35251881Speter */ 36251881Speter 37251881Speter#ifndef lint 38251881Speterstatic const char copyright[] = 39251881Speter"@(#) Copyright (c) 1989, 1993\n\ 40251881Speter The Regents of the University of California. All rights reserved.\n"; 41251881Speter#endif /* not lint */ 42289180Speter 43251881Speter#ifndef lint 44251881Speter#if 0 45251881Speterstatic char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; 46251881Speter#endif 47251881Speterstatic const char rcsid[] = 48251881Speter "$FreeBSD: head/sbin/ping/ping.c 102471 2002-08-27 08:09:37Z iedowse $"; 49251881Speter#endif /* not lint */ 50251881Speter 51251881Speter/* 52251881Speter * P I N G . C 53251881Speter * 54251881Speter * Using the Internet Control Message Protocol (ICMP) "ECHO" facility, 55251881Speter * measure round-trip-delays and packet loss across network paths. 56251881Speter * 57251881Speter * Author - 58251881Speter * Mike Muuss 59251881Speter * U. S. Army Ballistic Research Laboratory 60251881Speter * December, 1983 61251881Speter * 62251881Speter * Status - 63251881Speter * Public Domain. Distribution Unlimited. 64251881Speter * Bugs - 65251881Speter * More statistics could always be gathered. 66251881Speter * This program has to run SUID to ROOT to access the ICMP socket. 67251881Speter */ 68251881Speter 69251881Speter#include <sys/param.h> /* NB: we rely on this for <sys/types.h> */ 70251881Speter 71251881Speter#include <ctype.h> 72251881Speter#include <err.h> 73251881Speter#include <errno.h> 74251881Speter#include <math.h> 75251881Speter#include <netdb.h> 76251881Speter#include <signal.h> 77251881Speter#include <stdio.h> 78251881Speter#include <stdlib.h> 79251881Speter#include <string.h> 80251881Speter#include <sysexits.h> 81251881Speter#include <termios.h> 82251881Speter#include <unistd.h> 83251881Speter 84251881Speter#include <sys/socket.h> 85251881Speter#include <sys/time.h> 86251881Speter#include <sys/uio.h> 87251881Speter 88251881Speter#include <netinet/in.h> 89251881Speter#include <netinet/in_systm.h> 90251881Speter#include <netinet/ip.h> 91251881Speter#include <netinet/ip_icmp.h> 92251881Speter#include <netinet/ip_var.h> 93251881Speter#include <arpa/inet.h> 94251881Speter 95251881Speter#ifdef IPSEC 96251881Speter#include <netinet6/ipsec.h> 97251881Speter#endif /*IPSEC*/ 98251881Speter 99251881Speter#define INADDR_LEN ((int)sizeof(in_addr_t)) 100251881Speter#define PHDR_LEN ((int)sizeof(struct timeval)) 101251881Speter#define DEFDATALEN (64 - PHDR_LEN) /* default data length */ 102251881Speter#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */ 103251881Speter /* runs out of buffer space */ 104251881Speter#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN) 105251881Speter#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN) 106251881Speter#define MINICMPLEN ICMP_MINLEN 107251881Speter#define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - MINICMPLEN) 108251881Speter#define MAXWAIT 10 /* max seconds to wait for response */ 109251881Speter#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ 110251881Speter 111251881Speter#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 112251881Speter#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 113251881Speter#define SET(bit) (A(bit) |= B(bit)) 114251881Speter#define CLR(bit) (A(bit) &= (~B(bit))) 115251881Speter#define TST(bit) (A(bit) & B(bit)) 116251881Speter 117251881Speter/* various options */ 118251881Speterint options; 119251881Speter#define F_FLOOD 0x0001 120251881Speter#define F_INTERVAL 0x0002 121251881Speter#define F_NUMERIC 0x0004 122251881Speter#define F_PINGFILLED 0x0008 123251881Speter#define F_QUIET 0x0010 124251881Speter#define F_RROUTE 0x0020 125251881Speter#define F_SO_DEBUG 0x0040 126251881Speter#define F_SO_DONTROUTE 0x0080 127251881Speter#define F_VERBOSE 0x0100 128251881Speter#define F_QUIET2 0x0200 129251881Speter#define F_NOLOOP 0x0400 130251881Speter#define F_MTTL 0x0800 131251881Speter#define F_MIF 0x1000 132251881Speter#define F_AUDIBLE 0x2000 133251881Speter#ifdef IPSEC 134251881Speter#ifdef IPSEC_POLICY_IPSEC 135251881Speter#define F_POLICY 0x4000 136251881Speter#endif /*IPSEC_POLICY_IPSEC*/ 137251881Speter#endif /*IPSEC*/ 138251881Speter#define F_TTL 0x8000 139251881Speter#define F_MISSED 0x10000 140251881Speter 141251881Speter/* 142251881Speter * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 143251881Speter * number of received sequence numbers we can keep track of. Change 128 144251881Speter * to 8192 for complete accuracy... 145251881Speter */ 146251881Speter#define MAX_DUP_CHK (8 * 128) 147251881Speterint mx_dup_ck = MAX_DUP_CHK; 148251881Speterchar rcvd_tbl[MAX_DUP_CHK / 8]; 149251881Speter 150251881Speterstruct sockaddr_in whereto; /* who to ping */ 151251881Speterint datalen = DEFDATALEN; 152251881Speterint s; /* socket file descriptor */ 153251881Speteru_char outpack[MINICMPLEN + MAXPAYLOAD]; 154251881Speterchar BSPACE = '\b'; /* characters written for flood */ 155251881Speterchar BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ 156251881Speterchar DOT = '.'; 157251881Speterchar *hostname; 158251881Speterchar *shostname; 159251881Speterint ident; /* process id to identify our packets */ 160251881Speterint uid; /* cached uid for micro-optimization */ 161251881Speter 162251881Speter/* counters */ 163251881Speterlong npackets; /* max packets to transmit */ 164251881Speterlong nreceived; /* # of packets we got back */ 165251881Speterlong nrepeats; /* number of duplicates */ 166251881Speterlong ntransmitted; /* sequence # for outbound packets = #sent */ 167251881Speterlong nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 168251881Speterint interval = 1000; /* interval between packets, ms */ 169251881Speter 170251881Speter/* timing */ 171251881Speterint timing; /* flag to do timing */ 172251881Speterdouble tmin = 999999999.0; /* minimum round trip time */ 173251881Speterdouble tmax = 0.0; /* maximum round trip time */ 174251881Speterdouble tsum = 0.0; /* sum of all times, for doing average */ 175251881Speterdouble tsumsq = 0.0; /* sum of all times squared, for std. dev. */ 176251881Speter 177251881Spetervolatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */ 178251881Speterint reset_kerninfo; 179251881Spetervolatile sig_atomic_t siginfo_p; 180251881Speter 181251881Speterstatic void fill(char *, char *); 182251881Speterstatic u_short in_cksum(u_short *, int); 183251881Speterstatic void check_status(void); 184289180Speterstatic void finish(void) __dead2; 185289180Speterstatic void pinger(void); 186251881Speterstatic char *pr_addr(struct in_addr); 187251881Speterstatic void pr_icmph(struct icmp *); 188251881Speterstatic void pr_iph(struct ip *); 189251881Speterstatic void pr_pack(char *, int, struct sockaddr_in *, struct timeval *); 190251881Speterstatic void pr_retip(struct ip *); 191251881Speterstatic void status(int); 192251881Speterstatic void stopit(int); 193251881Speterstatic void tvsub(struct timeval *, struct timeval *); 194251881Speterstatic void usage(void) __dead2; 195251881Speter 196251881Speterint 197251881Spetermain(argc, argv) 198362181Sdim int argc; 199251881Speter char *const *argv; 200289180Speter{ 201251881Speter struct in_addr ifaddr; 202251881Speter struct iovec iov; 203251881Speter struct msghdr msg; 204251881Speter struct sigaction si_sa; 205251881Speter struct sockaddr_in from, sin; 206251881Speter struct termios ts; 207251881Speter struct timeval last, intvl; 208251881Speter struct hostent *hp; 209251881Speter struct sockaddr_in *to; 210251881Speter double t; 211251881Speter u_char *datap, packet[IP_MAXPACKET]; 212251881Speter char *ep, *source, *target; 213251881Speter#ifdef IPSEC_POLICY_IPSEC 214251881Speter char *policy_in, *policy_out; 215251881Speter#endif 216251881Speter u_long alarmtimeout, ultmp; 217251881Speter int ch, hold, i, packlen, preload, sockerrno, almost_done = 0, ttl; 218251881Speter char ctrl[CMSG_SPACE(sizeof(struct timeval))]; 219251881Speter char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; 220251881Speter#ifdef IP_OPTIONS 221251881Speter char rspace[MAX_IPOPTLEN]; /* record route space */ 222251881Speter#endif 223251881Speter unsigned char mttl, loop; 224251881Speter 225251881Speter source = NULL; 226251881Speter#ifdef IPSEC_POLICY_IPSEC 227251881Speter policy_in = policy_out = NULL; 228251881Speter#endif 229251881Speter 230251881Speter /* 231251881Speter * Do the stuff that we need root priv's for *first*, and 232251881Speter * then drop our setuid bit. Save error reporting for 233251881Speter * after arg parsing. 234251881Speter */ 235251881Speter s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 236251881Speter sockerrno = errno; 237251881Speter 238251881Speter setuid(getuid()); 239251881Speter uid = getuid(); 240251881Speter 241251881Speter alarmtimeout = preload = 0; 242251881Speter 243251881Speter datap = &outpack[MINICMPLEN + PHDR_LEN]; 244251881Speter while ((ch = getopt(argc, argv, 245251881Speter "AI:LQRS:T:c:adfi:l:m:np:qrs:t:v" 246251881Speter#ifdef IPSEC 247251881Speter#ifdef IPSEC_POLICY_IPSEC 248251881Speter "P:" 249251881Speter#endif /*IPSEC_POLICY_IPSEC*/ 250251881Speter#endif /*IPSEC*/ 251251881Speter )) != -1) 252251881Speter { 253251881Speter switch(ch) { 254251881Speter case 'A': 255251881Speter options |= F_MISSED; 256251881Speter break; 257251881Speter case 'a': 258251881Speter options |= F_AUDIBLE; 259251881Speter break; 260251881Speter case 'c': 261251881Speter ultmp = strtoul(optarg, &ep, 0); 262251881Speter if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp) 263251881Speter errx(EX_USAGE, 264251881Speter "invalid count of packets to transmit: `%s'", 265251881Speter optarg); 266251881Speter npackets = ultmp; 267251881Speter break; 268251881Speter case 'd': 269251881Speter options |= F_SO_DEBUG; 270251881Speter break; 271251881Speter case 'f': 272251881Speter if (uid) { 273251881Speter errno = EPERM; 274251881Speter err(EX_NOPERM, "-f flag"); 275251881Speter } 276251881Speter options |= F_FLOOD; 277251881Speter setbuf(stdout, (char *)NULL); 278251881Speter break; 279251881Speter case 'i': /* wait between sending packets */ 280251881Speter t = strtod(optarg, &ep) * 1000.0; 281251881Speter if (*ep || ep == optarg || t > (double)INT_MAX) 282251881Speter errx(EX_USAGE, "invalid timing interval: `%s'", 283251881Speter optarg); 284251881Speter options |= F_INTERVAL; 285251881Speter interval = (int)t; 286251881Speter if (uid && interval < 1000) { 287251881Speter errno = EPERM; 288251881Speter err(EX_NOPERM, "-i interval too short"); 289251881Speter } 290251881Speter break; 291251881Speter case 'I': /* multicast interface */ 292251881Speter if (inet_aton(optarg, &ifaddr) == 0) 293251881Speter errx(EX_USAGE, 294251881Speter "invalid multicast interface: `%s'", 295251881Speter optarg); 296251881Speter options |= F_MIF; 297251881Speter break; 298251881Speter case 'l': 299251881Speter ultmp = strtoul(optarg, &ep, 0); 300251881Speter if (*ep || ep == optarg || ultmp > INT_MAX) 301251881Speter errx(EX_USAGE, 302251881Speter "invalid preload value: `%s'", optarg); 303289180Speter if (uid) { 304289180Speter errno = EPERM; 305251881Speter err(EX_NOPERM, "-l flag"); 306251881Speter } 307251881Speter preload = ultmp; 308251881Speter break; 309251881Speter case 'L': 310251881Speter options |= F_NOLOOP; 311251881Speter loop = 0; 312251881Speter break; 313251881Speter case 'm': /* TTL */ 314251881Speter ultmp = strtoul(optarg, &ep, 0); 315251881Speter if (*ep || ep == optarg || ultmp > 255) 316251881Speter errx(EX_USAGE, "invalid TTL: `%s'", optarg); 317251881Speter ttl = ultmp; 318251881Speter options |= F_TTL; 319251881Speter break; 320251881Speter case 'n': 321251881Speter options |= F_NUMERIC; 322251881Speter break; 323251881Speter case 'p': /* fill buffer with user pattern */ 324251881Speter options |= F_PINGFILLED; 325251881Speter fill((char *)datap, optarg); 326251881Speter break; 327251881Speter case 'Q': 328251881Speter options |= F_QUIET2; 329251881Speter break; 330251881Speter case 'q': 331251881Speter options |= F_QUIET; 332251881Speter break; 333251881Speter case 'R': 334251881Speter options |= F_RROUTE; 335251881Speter break; 336251881Speter case 'r': 337251881Speter options |= F_SO_DONTROUTE; 338251881Speter break; 339251881Speter case 's': /* size of packet to send */ 340251881Speter if (uid) { 341251881Speter errno = EPERM; 342251881Speter err(EX_NOPERM, "-s flag"); 343251881Speter } 344251881Speter ultmp = strtoul(optarg, &ep, 0); 345251881Speter if (ultmp > MAXPAYLOAD) 346251881Speter errx(EX_USAGE, 347251881Speter "packet size too large: %lu > %u", 348251881Speter ultmp, MAXPAYLOAD); 349251881Speter if (*ep || ep == optarg) 350251881Speter errx(EX_USAGE, "invalid packet size: `%s'", 351251881Speter optarg); 352251881Speter datalen = ultmp; 353251881Speter break; 354251881Speter case 'S': 355251881Speter source = optarg; 356251881Speter break; 357251881Speter case 't': 358251881Speter alarmtimeout = strtoul(optarg, &ep, 0); 359251881Speter if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) 360251881Speter errx(EX_USAGE, "invalid timeout: `%s'", 361251881Speter optarg); 362251881Speter if (alarmtimeout > MAXALARM) 363251881Speter errx(EX_USAGE, "invalid timeout: `%s' > %d", 364251881Speter optarg, MAXALARM); 365251881Speter alarm((int)alarmtimeout); 366251881Speter break; 367251881Speter case 'T': /* multicast TTL */ 368251881Speter ultmp = strtoul(optarg, &ep, 0); 369251881Speter if (*ep || ep == optarg || ultmp > 255) 370251881Speter errx(EX_USAGE, "invalid multicast TTL: `%s'", 371251881Speter optarg); 372251881Speter mttl = ultmp; 373251881Speter options |= F_MTTL; 374251881Speter break; 375251881Speter case 'v': 376251881Speter options |= F_VERBOSE; 377251881Speter break; 378251881Speter#ifdef IPSEC 379251881Speter#ifdef IPSEC_POLICY_IPSEC 380251881Speter case 'P': 381251881Speter options |= F_POLICY; 382251881Speter if (!strncmp("in", optarg, 2)) 383251881Speter policy_in = strdup(optarg); 384251881Speter else if (!strncmp("out", optarg, 3)) 385251881Speter policy_out = strdup(optarg); 386251881Speter else 387251881Speter errx(1, "invalid security policy"); 388251881Speter break; 389251881Speter#endif /*IPSEC_POLICY_IPSEC*/ 390251881Speter#endif /*IPSEC*/ 391251881Speter default: 392251881Speter usage(); 393251881Speter } 394251881Speter } 395251881Speter 396251881Speter if (argc - optind != 1) 397251881Speter usage(); 398251881Speter target = argv[optind]; 399251881Speter 400251881Speter if (source) { 401251881Speter bzero((char *)&sin, sizeof(sin)); 402251881Speter sin.sin_family = AF_INET; 403251881Speter if (inet_aton(source, &sin.sin_addr) != 0) { 404251881Speter shostname = source; 405251881Speter } else { 406251881Speter hp = gethostbyname2(source, AF_INET); 407251881Speter if (!hp) 408251881Speter errx(EX_NOHOST, "cannot resolve %s: %s", 409251881Speter source, hstrerror(h_errno)); 410251881Speter 411251881Speter sin.sin_len = sizeof sin; 412362181Sdim if (hp->h_length > sizeof(sin.sin_addr) || 413251881Speter hp->h_length < 0) 414251881Speter errx(1, "gethostbyname2: illegal address"); 415251881Speter memcpy(&sin.sin_addr, hp->h_addr_list[0], 416251881Speter sizeof(sin.sin_addr)); 417251881Speter (void)strncpy(snamebuf, hp->h_name, 418251881Speter sizeof(snamebuf) - 1); 419251881Speter snamebuf[sizeof(snamebuf) - 1] = '\0'; 420251881Speter shostname = snamebuf; 421251881Speter } 422251881Speter if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1) 423251881Speter err(1, "bind"); 424251881Speter } 425251881Speter 426251881Speter bzero(&whereto, sizeof(whereto)); 427251881Speter to = &whereto; 428251881Speter to->sin_family = AF_INET; 429251881Speter to->sin_len = sizeof *to; 430251881Speter if (inet_aton(target, &to->sin_addr) != 0) { 431251881Speter hostname = target; 432251881Speter } else { 433251881Speter hp = gethostbyname2(target, AF_INET); 434251881Speter if (!hp) 435251881Speter errx(EX_NOHOST, "cannot resolve %s: %s", 436251881Speter target, hstrerror(h_errno)); 437251881Speter 438251881Speter if (hp->h_length > sizeof(to->sin_addr)) 439251881Speter errx(1, "gethostbyname2 returned an illegal address"); 440251881Speter memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr); 441251881Speter (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 442251881Speter hnamebuf[sizeof(hnamebuf) - 1] = '\0'; 443251881Speter hostname = hnamebuf; 444251881Speter } 445251881Speter 446251881Speter if (options & F_FLOOD && options & F_INTERVAL) 447251881Speter errx(EX_USAGE, "-f and -i: incompatible options"); 448251881Speter 449251881Speter if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 450251881Speter errx(EX_USAGE, 451251881Speter "-f flag cannot be used with multicast destination"); 452251881Speter if (options & (F_MIF | F_NOLOOP | F_MTTL) 453251881Speter && !IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 454362181Sdim errx(EX_USAGE, 455362181Sdim "-I, -L, -T flags cannot be used with unicast destination"); 456251881Speter 457251881Speter if (datalen >= PHDR_LEN) /* can we time transfer */ 458251881Speter timing = 1; 459251881Speter packlen = MAXIPLEN + MAXICMPLEN + datalen; 460251881Speter packlen = packlen > IP_MAXPACKET ? IP_MAXPACKET : packlen; 461251881Speter 462251881Speter if (!(options & F_PINGFILLED)) 463362181Sdim for (i = PHDR_LEN; i < datalen; ++i) 464251881Speter *datap++ = i; 465251881Speter 466251881Speter ident = getpid() & 0xFFFF; 467251881Speter 468251881Speter if (s < 0) { 469251881Speter errno = sockerrno; 470251881Speter err(EX_OSERR, "socket"); 471251881Speter } 472251881Speter hold = 1; 473251881Speter if (options & F_SO_DEBUG) 474251881Speter (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 475251881Speter sizeof(hold)); 476251881Speter if (options & F_SO_DONTROUTE) 477251881Speter (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 478251881Speter sizeof(hold)); 479251881Speter#ifdef IPSEC 480251881Speter#ifdef IPSEC_POLICY_IPSEC 481251881Speter if (options & F_POLICY) { 482251881Speter char *buf; 483251881Speter if (policy_in != NULL) { 484251881Speter buf = ipsec_set_policy(policy_in, strlen(policy_in)); 485251881Speter if (buf == NULL) 486251881Speter errx(EX_CONFIG, "%s", ipsec_strerror()); 487251881Speter if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, 488251881Speter buf, ipsec_get_policylen(buf)) < 0) 489251881Speter err(EX_CONFIG, 490251881Speter "ipsec policy cannot be configured"); 491251881Speter free(buf); 492251881Speter } 493251881Speter 494251881Speter if (policy_out != NULL) { 495251881Speter buf = ipsec_set_policy(policy_out, strlen(policy_out)); 496251881Speter if (buf == NULL) 497251881Speter errx(EX_CONFIG, "%s", ipsec_strerror()); 498251881Speter if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, 499251881Speter buf, ipsec_get_policylen(buf)) < 0) 500251881Speter err(EX_CONFIG, 501251881Speter "ipsec policy cannot be configured"); 502251881Speter free(buf); 503251881Speter } 504251881Speter } 505251881Speter#endif /*IPSEC_POLICY_IPSEC*/ 506251881Speter#endif /*IPSEC*/ 507251881Speter 508251881Speter /* record route option */ 509251881Speter if (options & F_RROUTE) { 510251881Speter#ifdef IP_OPTIONS 511251881Speter bzero(rspace, sizeof(rspace)); 512251881Speter rspace[IPOPT_OPTVAL] = IPOPT_RR; 513251881Speter rspace[IPOPT_OLEN] = sizeof(rspace) - 1; 514251881Speter rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 515251881Speter rspace[sizeof(rspace) - 1] = IPOPT_EOL; 516251881Speter if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, 517251881Speter sizeof(rspace)) < 0) 518251881Speter err(EX_OSERR, "setsockopt IP_OPTIONS"); 519251881Speter#else 520251881Speter errx(EX_UNAVAILABLE, 521251881Speter "record route not available in this implementation"); 522251881Speter#endif /* IP_OPTIONS */ 523251881Speter } 524251881Speter 525251881Speter if (options & F_TTL) { 526251881Speter if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, 527251881Speter sizeof(ttl)) < 0) { 528251881Speter err(EX_OSERR, "setsockopt IP_TTL"); 529251881Speter } 530251881Speter } 531251881Speter if (options & F_NOLOOP) { 532251881Speter if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, 533251881Speter sizeof(loop)) < 0) { 534251881Speter err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); 535251881Speter } 536251881Speter } 537251881Speter if (options & F_MTTL) { 538251881Speter if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, 539251881Speter sizeof(mttl)) < 0) { 540251881Speter err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); 541251881Speter } 542251881Speter } 543251881Speter if (options & F_MIF) { 544251881Speter if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, 545251881Speter sizeof(ifaddr)) < 0) { 546251881Speter err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); 547251881Speter } 548289180Speter } 549289180Speter#ifdef SO_TIMESTAMP 550289180Speter { int on = 1; 551289180Speter if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) 552289180Speter err(EX_OSERR, "setsockopt SO_TIMESTAMP"); 553289180Speter } 554289180Speter#endif 555251881Speter 556251881Speter /* 557251881Speter * When pinging the broadcast address, you can get a lot of answers. 558251881Speter * Doing something so evil is useful if you are trying to stress the 559251881Speter * ethernet, or just want to fill the arp cache to get some stuff for 560251881Speter * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast 561251881Speter * or multicast pings if they wish. 562251881Speter */ 563251881Speter 564251881Speter /* 565251881Speter * XXX receive buffer needs undetermined space for mbuf overhead 566251881Speter * as well. 567251881Speter */ 568251881Speter hold = IP_MAXPACKET + 128; 569251881Speter (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 570251881Speter sizeof(hold)); 571251881Speter 572251881Speter if (!uid) { 573251881Speter (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold, 574251881Speter sizeof(hold)); 575251881Speter } 576251881Speter 577251881Speter if (to->sin_family == AF_INET) { 578251881Speter (void)printf("PING %s (%s)", hostname, 579251881Speter inet_ntoa(to->sin_addr)); 580251881Speter if (source) 581251881Speter (void)printf(" from %s", shostname); 582251881Speter (void)printf(": %d data bytes\n", datalen); 583251881Speter } else 584251881Speter (void)printf("PING %s: %d data bytes\n", hostname, datalen); 585251881Speter 586251881Speter /* 587251881Speter * Use sigaction() instead of signal() to get unambiguous semantics, 588251881Speter * in particular with SA_RESTART not set. 589251881Speter */ 590251881Speter 591251881Speter sigemptyset(&si_sa.sa_mask); 592251881Speter si_sa.sa_flags = 0; 593251881Speter 594251881Speter si_sa.sa_handler = stopit; 595251881Speter if (sigaction(SIGINT, &si_sa, 0) == -1) { 596251881Speter err(EX_OSERR, "sigaction SIGINT"); 597251881Speter } 598251881Speter 599251881Speter si_sa.sa_handler = status; 600251881Speter if (sigaction(SIGINFO, &si_sa, 0) == -1) { 601251881Speter err(EX_OSERR, "sigaction"); 602251881Speter } 603251881Speter 604251881Speter if (alarmtimeout > 0) { 605251881Speter si_sa.sa_handler = stopit; 606251881Speter if (sigaction(SIGALRM, &si_sa, 0) == -1) 607251881Speter err(EX_OSERR, "sigaction SIGALRM"); 608251881Speter } 609251881Speter 610251881Speter bzero(&msg, sizeof(msg)); 611251881Speter msg.msg_name = (caddr_t)&from; 612251881Speter msg.msg_iov = &iov; 613251881Speter msg.msg_iovlen = 1; 614251881Speter#ifdef SO_TIMESTAMP 615251881Speter msg.msg_control = (caddr_t)ctrl; 616251881Speter#endif 617251881Speter iov.iov_base = packet; 618251881Speter iov.iov_len = packlen; 619251881Speter 620251881Speter if (tcgetattr(STDOUT_FILENO, &ts) != -1) { 621251881Speter reset_kerninfo = !(ts.c_lflag & NOKERNINFO); 622251881Speter ts.c_lflag |= NOKERNINFO; 623251881Speter tcsetattr(STDOUT_FILENO, TCSANOW, &ts); 624251881Speter } 625251881Speter 626251881Speter if (preload == 0) 627251881Speter pinger(); /* send the first ping */ 628251881Speter else { 629251881Speter if (npackets != 0 && preload > npackets) 630251881Speter preload = npackets; 631251881Speter while (preload--) /* fire off them quickies */ 632251881Speter pinger(); 633251881Speter } 634251881Speter (void)gettimeofday(&last, NULL); 635251881Speter 636251881Speter if (options & F_FLOOD) { 637251881Speter intvl.tv_sec = 0; 638251881Speter intvl.tv_usec = 10000; 639251881Speter } else { 640251881Speter intvl.tv_sec = interval / 1000; 641251881Speter intvl.tv_usec = interval % 1000 * 1000; 642251881Speter } 643251881Speter 644251881Speter while (!finish_up) { 645251881Speter int cc; 646251881Speter int n; 647251881Speter struct timeval timeout, now; 648251881Speter fd_set rfds; 649251881Speter 650251881Speter check_status(); 651251881Speter FD_ZERO(&rfds); 652251881Speter FD_SET(s, &rfds); 653251881Speter (void)gettimeofday(&now, NULL); 654251881Speter timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; 655251881Speter timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; 656251881Speter while (timeout.tv_usec < 0) { 657251881Speter timeout.tv_usec += 1000000; 658251881Speter timeout.tv_sec--; 659251881Speter } 660251881Speter while (timeout.tv_usec >= 1000000) { 661251881Speter timeout.tv_usec -= 1000000; 662251881Speter timeout.tv_sec++; 663251881Speter } 664251881Speter if (timeout.tv_sec < 0) 665251881Speter timeout.tv_sec = timeout.tv_usec = 0; 666251881Speter n = select(s + 1, &rfds, NULL, NULL, &timeout); 667251881Speter if (n < 0) 668251881Speter continue; /* Must be EINTR. */ 669251881Speter if (n == 1) { 670251881Speter struct timeval *t = 0; 671251881Speter#ifdef SO_TIMESTAMP 672251881Speter struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; 673251881Speter 674251881Speter msg.msg_controllen = sizeof(ctrl); 675251881Speter#endif 676251881Speter msg.msg_namelen = sizeof(from); 677251881Speter if ((cc = recvmsg(s, &msg, 0)) < 0) { 678251881Speter if (errno == EINTR) 679251881Speter continue; 680251881Speter warn("recvmsg"); 681251881Speter continue; 682251881Speter } 683251881Speter#ifdef SO_TIMESTAMP 684251881Speter if (cmsg->cmsg_level == SOL_SOCKET && 685251881Speter cmsg->cmsg_type == SCM_TIMESTAMP && 686251881Speter cmsg->cmsg_len == CMSG_LEN(sizeof *t)) { 687251881Speter /* Copy to avoid alignment problems: */ 688251881Speter memcpy(&now,CMSG_DATA(cmsg),sizeof(now)); 689251881Speter t = &now; 690251881Speter } 691251881Speter#endif 692251881Speter if (t == 0) { 693251881Speter (void)gettimeofday(&now, NULL); 694251881Speter t = &now; 695251881Speter } 696251881Speter pr_pack((char *)packet, cc, &from, t); 697251881Speter if (npackets && nreceived >= npackets) 698251881Speter break; 699251881Speter } 700251881Speter if (n == 0 || options & F_FLOOD) { 701251881Speter if (!npackets || ntransmitted < npackets) 702251881Speter pinger(); 703251881Speter else { 704251881Speter if (almost_done) 705251881Speter break; 706251881Speter almost_done = 1; 707251881Speter intvl.tv_usec = 0; 708251881Speter if (nreceived) { 709251881Speter intvl.tv_sec = 2 * tmax / 1000; 710251881Speter if (!intvl.tv_sec) 711251881Speter intvl.tv_sec = 1; 712251881Speter } else 713251881Speter intvl.tv_sec = MAXWAIT; 714251881Speter } 715251881Speter (void)gettimeofday(&last, NULL); 716251881Speter 717251881Speter if (ntransmitted - nreceived - 1 > nmissedmax) { 718251881Speter nmissedmax = ntransmitted - nreceived - 1; 719251881Speter if (options & F_MISSED) 720251881Speter (void)write(STDOUT_FILENO, &BBELL, 1); 721251881Speter } 722251881Speter } 723251881Speter } 724251881Speter finish(); 725251881Speter /* NOTREACHED */ 726251881Speter exit(0); /* Make the compiler happy */ 727251881Speter} 728251881Speter 729251881Speter/* 730251881Speter * stopit -- 731251881Speter * Set the global bit that causes the main loop to quit. 732251881Speter * Do NOT call finish() from here, since finish() does far too much 733251881Speter * to be called from a signal handler. 734251881Speter */ 735251881Spetervoid 736251881Speterstopit(sig) 737251881Speter int sig __unused; 738251881Speter{ 739251881Speter 740251881Speter finish_up = 1; 741251881Speter} 742251881Speter 743251881Speter/* 744251881Speter * pinger -- 745251881Speter * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 746251881Speter * will be added on by the kernel. The ID field is our UNIX process ID, 747251881Speter * and the sequence number is an ascending integer. The first PHDR_LEN 748251881Speter * bytes of the data portion are used to hold a UNIX "timeval" struct in 749251881Speter * host byte-order, to compute the round-trip time. 750251881Speter */ 751251881Speterstatic void 752251881Speterpinger(void) 753251881Speter{ 754251881Speter struct icmp *icp; 755251881Speter int cc, i; 756251881Speter 757251881Speter icp = (struct icmp *)outpack; 758251881Speter icp->icmp_type = ICMP_ECHO; 759251881Speter icp->icmp_code = 0; 760251881Speter icp->icmp_cksum = 0; 761251881Speter icp->icmp_seq = htons(ntransmitted); 762251881Speter icp->icmp_id = ident; /* ID */ 763251881Speter 764251881Speter CLR(ntransmitted % mx_dup_ck); 765251881Speter 766251881Speter if (timing) 767251881Speter (void)gettimeofday((struct timeval *)&outpack[MINICMPLEN], 768251881Speter (struct timezone *)NULL); 769251881Speter 770251881Speter cc = MINICMPLEN + datalen; 771251881Speter 772251881Speter /* compute ICMP checksum here */ 773251881Speter icp->icmp_cksum = in_cksum((u_short *)icp, cc); 774251881Speter 775251881Speter i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr *)&whereto, 776251881Speter sizeof(whereto)); 777251881Speter 778251881Speter if (i < 0 || i != cc) { 779251881Speter if (i < 0) { 780251881Speter if (options & F_FLOOD && errno == ENOBUFS) { 781251881Speter usleep(FLOOD_BACKOFF); 782251881Speter return; 783251881Speter } 784251881Speter warn("sendto"); 785251881Speter } else { 786251881Speter warn("%s: partial write: %d of %d bytes", 787251881Speter hostname, i, cc); 788251881Speter } 789251881Speter } 790251881Speter ntransmitted++; 791251881Speter if (!(options & F_QUIET) && options & F_FLOOD) 792251881Speter (void)write(STDOUT_FILENO, &DOT, 1); 793251881Speter} 794251881Speter 795251881Speter/* 796251881Speter * pr_pack -- 797251881Speter * Print out the packet, if it came from us. This logic is necessary 798251881Speter * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 799251881Speter * which arrive ('tis only fair). This permits multiple copies of this 800251881Speter * program to be run without having intermingled output (or statistics!). 801251881Speter */ 802251881Speterstatic void 803251881Speterpr_pack(buf, cc, from, tv) 804251881Speter char *buf; 805251881Speter int cc; 806251881Speter struct sockaddr_in *from; 807251881Speter struct timeval *tv; 808251881Speter{ 809251881Speter struct icmp *icp; 810251881Speter struct ip *ip; 811251881Speter struct in_addr ina; 812251881Speter struct timeval *tp; 813251881Speter u_char *cp, *dp; 814251881Speter double triptime; 815251881Speter int dupflag, hlen, i, j, seq; 816251881Speter static int old_rrlen; 817251881Speter static char old_rr[MAX_IPOPTLEN]; 818251881Speter 819251881Speter /* Check the IP header */ 820251881Speter ip = (struct ip *)buf; 821251881Speter hlen = ip->ip_hl << 2; 822251881Speter if (cc < hlen + ICMP_MINLEN) { 823251881Speter if (options & F_VERBOSE) 824251881Speter warn("packet too short (%d bytes) from %s", cc, 825251881Speter inet_ntoa(from->sin_addr)); 826251881Speter return; 827251881Speter } 828251881Speter 829251881Speter /* Now the ICMP part */ 830251881Speter cc -= hlen; 831251881Speter icp = (struct icmp *)(buf + hlen); 832251881Speter if (icp->icmp_type == ICMP_ECHOREPLY) { 833251881Speter if (icp->icmp_id != ident) 834251881Speter return; /* 'Twas not our ECHO */ 835251881Speter ++nreceived; 836251881Speter triptime = 0.0; 837251881Speter if (timing) { 838251881Speter struct timeval tv1; 839251881Speter#ifndef icmp_data 840251881Speter tp = (struct timeval *)&icp->icmp_ip; 841251881Speter#else 842251881Speter tp = (struct timeval *)icp->icmp_data; 843362181Sdim#endif 844362181Sdim /* Avoid unaligned data (cannot use memcpy) */ 845362181Sdim bcopy(tp, &tv1, sizeof(tv1)); 846362181Sdim tvsub(tv, &tv1); 847362181Sdim triptime = ((double)tv->tv_sec) * 1000.0 + 848362181Sdim ((double)tv->tv_usec) / 1000.0; 849362181Sdim tsum += triptime; 850362181Sdim tsumsq += triptime * triptime; 851362181Sdim if (triptime < tmin) 852362181Sdim tmin = triptime; 853362181Sdim if (triptime > tmax) 854362181Sdim tmax = triptime; 855362181Sdim } 856362181Sdim 857362181Sdim seq = ntohs(icp->icmp_seq); 858362181Sdim 859362181Sdim if (TST(seq % mx_dup_ck)) { 860362181Sdim ++nrepeats; 861362181Sdim --nreceived; 862362181Sdim dupflag = 1; 863362181Sdim } else { 864362181Sdim SET(seq % mx_dup_ck); 865362181Sdim dupflag = 0; 866362181Sdim } 867362181Sdim 868362181Sdim if (options & F_QUIET) 869362181Sdim return; 870362181Sdim 871362181Sdim if (options & F_FLOOD) 872362181Sdim (void)write(STDOUT_FILENO, &BSPACE, 1); 873362181Sdim else { 874362181Sdim (void)printf("%d bytes from %s: icmp_seq=%u", cc, 875362181Sdim inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 876362181Sdim seq); 877362181Sdim (void)printf(" ttl=%d", ip->ip_ttl); 878362181Sdim if (timing) 879362181Sdim (void)printf(" time=%.3f ms", triptime); 880362181Sdim if (dupflag) 881362181Sdim (void)printf(" (DUP!)"); 882362181Sdim if (options & F_AUDIBLE) 883362181Sdim (void)write(STDOUT_FILENO, &BBELL, 1); 884362181Sdim /* check the data */ 885362181Sdim cp = (u_char*)&icp->icmp_data[PHDR_LEN]; 886362181Sdim dp = &outpack[MINICMPLEN + PHDR_LEN]; 887362181Sdim for (i = PHDR_LEN; i < datalen; ++i, ++cp, ++dp) { 888362181Sdim if (*cp != *dp) { 889362181Sdim (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 890362181Sdim i, *dp, *cp); 891362181Sdim (void)printf("\ncp:"); 892362181Sdim cp = (u_char*)&icp->icmp_data[0]; 893362181Sdim for (i = 0; i < datalen; ++i, ++cp) { 894362181Sdim if ((i % 32) == 8) 895362181Sdim (void)printf("\n\t"); 896362181Sdim (void)printf("%x ", *cp); 897362181Sdim } 898362181Sdim (void)printf("\ndp:"); 899362181Sdim cp = &outpack[MINICMPLEN]; 900362181Sdim for (i = 0; i < datalen; ++i, ++cp) { 901362181Sdim if ((i % 32) == 8) 902362181Sdim (void)printf("\n\t"); 903362181Sdim (void)printf("%x ", *cp); 904362181Sdim } 905362181Sdim break; 906362181Sdim } 907362181Sdim } 908362181Sdim } 909362181Sdim } else { 910362181Sdim /* 911362181Sdim * We've got something other than an ECHOREPLY. 912362181Sdim * See if it's a reply to something that we sent. 913362181Sdim * We can compare IP destination, protocol, 914362181Sdim * and ICMP type and ID. 915362181Sdim * 916362181Sdim * Only print all the error messages if we are running 917251881Speter * as root to avoid leaking information not normally 918251881Speter * available to those not running as root. 919251881Speter */ 920251881Speter#ifndef icmp_data 921251881Speter struct ip *oip = &icp->icmp_ip; 922251881Speter#else 923251881Speter struct ip *oip = (struct ip *)icp->icmp_data; 924251881Speter#endif 925251881Speter struct icmp *oicmp = (struct icmp *)(oip + 1); 926251881Speter 927251881Speter if (((options & F_VERBOSE) && uid == 0) || 928251881Speter (!(options & F_QUIET2) && 929251881Speter (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) && 930251881Speter (oip->ip_p == IPPROTO_ICMP) && 931251881Speter (oicmp->icmp_type == ICMP_ECHO) && 932251881Speter (oicmp->icmp_id == ident))) { 933251881Speter (void)printf("%d bytes from %s: ", cc, 934251881Speter pr_addr(from->sin_addr)); 935251881Speter pr_icmph(icp); 936251881Speter } else 937251881Speter return; 938251881Speter } 939251881Speter 940251881Speter /* Display any IP options */ 941251881Speter cp = (u_char *)buf + sizeof(struct ip); 942251881Speter 943251881Speter for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 944251881Speter switch (*cp) { 945251881Speter case IPOPT_EOL: 946362181Sdim hlen = 0; 947362181Sdim break; 948362181Sdim case IPOPT_LSRR: 949362181Sdim (void)printf("\nLSRR: "); 950251881Speter j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1; 951251881Speter hlen -= 2; 952251881Speter cp += 2; 953251881Speter if (j >= INADDR_LEN && j <= hlen - INADDR_LEN) { 954251881Speter for (;;) { 955251881Speter bcopy(++cp, &ina.s_addr, INADDR_LEN); 956251881Speter if (ina.s_addr == 0) 957251881Speter (void)printf("\t0.0.0.0"); 958251881Speter else 959251881Speter (void)printf("\t%s", 960251881Speter pr_addr(ina)); 961251881Speter hlen -= INADDR_LEN; 962251881Speter cp += INADDR_LEN - 1; 963251881Speter j -= INADDR_LEN; 964251881Speter if (j < INADDR_LEN) 965251881Speter break; 966251881Speter (void)putchar('\n'); 967251881Speter } 968251881Speter } else 969251881Speter (void)printf("\t(truncated route)\n"); 970251881Speter break; 971251881Speter case IPOPT_RR: 972251881Speter j = cp[IPOPT_OLEN]; /* get length */ 973251881Speter i = cp[IPOPT_OFFSET]; /* and pointer */ 974251881Speter hlen -= 2; 975251881Speter cp += 2; 976251881Speter if (i > j) 977251881Speter i = j; 978251881Speter i = i - IPOPT_MINOFF + 1; 979251881Speter if (i < 0 || i > (hlen - (int)sizeof(struct ip))) { 980251881Speter old_rrlen = 0; 981251881Speter continue; 982251881Speter } 983251881Speter if (i == old_rrlen 984251881Speter && !bcmp((char *)cp, old_rr, i) 985251881Speter && !(options & F_FLOOD)) { 986251881Speter (void)printf("\t(same route)"); 987362181Sdim hlen -= i; 988251881Speter cp += i; 989251881Speter break; 990251881Speter } 991251881Speter old_rrlen = i; 992251881Speter bcopy((char *)cp, old_rr, i); 993251881Speter 994251881Speter (void)printf("\nRR: "); 995251881Speter 996251881Speter if (i >= INADDR_LEN && 997251881Speter i <= hlen - (int)sizeof(struct ip)) { 998362181Sdim for (;;) { 999362181Sdim bcopy(++cp, &ina.s_addr, INADDR_LEN); 1000362181Sdim if (ina.s_addr == 0) 1001362181Sdim (void)printf("\t0.0.0.0"); 1002362181Sdim else 1003251881Speter (void)printf("\t%s", 1004251881Speter pr_addr(ina)); 1005251881Speter hlen -= INADDR_LEN; 1006251881Speter cp += INADDR_LEN - 1; 1007251881Speter i -= INADDR_LEN; 1008251881Speter if (i < INADDR_LEN) 1009251881Speter break; 1010251881Speter (void)putchar('\n'); 1011251881Speter } 1012251881Speter } else 1013251881Speter (void)printf("\t(truncated route)"); 1014251881Speter break; 1015251881Speter case IPOPT_NOP: 1016251881Speter (void)printf("\nNOP"); 1017251881Speter break; 1018251881Speter default: 1019251881Speter (void)printf("\nunknown option %x", *cp); 1020251881Speter break; 1021251881Speter } 1022251881Speter if (!(options & F_FLOOD)) { 1023251881Speter (void)putchar('\n'); 1024251881Speter (void)fflush(stdout); 1025251881Speter } 1026251881Speter} 1027251881Speter 1028251881Speter/* 1029251881Speter * in_cksum -- 1030251881Speter * Checksum routine for Internet Protocol family headers (C Version) 1031251881Speter */ 1032251881Speteru_short 1033251881Speterin_cksum(addr, len) 1034251881Speter u_short *addr; 1035251881Speter int len; 1036251881Speter{ 1037251881Speter int nleft, sum; 1038251881Speter u_short *w; 1039251881Speter union { 1040251881Speter u_short us; 1041251881Speter u_char uc[2]; 1042251881Speter } last; 1043251881Speter u_short answer; 1044251881Speter 1045251881Speter nleft = len; 1046251881Speter sum = 0; 1047251881Speter w = addr; 1048251881Speter 1049251881Speter /* 1050251881Speter * Our algorithm is simple, using a 32 bit accumulator (sum), we add 1051251881Speter * sequential 16 bit words to it, and at the end, fold back all the 1052251881Speter * carry bits from the top 16 bits into the lower 16 bits. 1053251881Speter */ 1054251881Speter while (nleft > 1) { 1055251881Speter sum += *w++; 1056251881Speter nleft -= 2; 1057251881Speter } 1058251881Speter 1059251881Speter /* mop up an odd byte, if necessary */ 1060251881Speter if (nleft == 1) { 1061251881Speter last.uc[0] = *(u_char *)w; 1062251881Speter last.uc[1] = 0; 1063251881Speter sum += last.us; 1064251881Speter } 1065251881Speter 1066251881Speter /* add back carry outs from top 16 bits to low 16 bits */ 1067251881Speter sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 1068251881Speter sum += (sum >> 16); /* add carry */ 1069251881Speter answer = ~sum; /* truncate to 16 bits */ 1070251881Speter return(answer); 1071251881Speter} 1072251881Speter 1073251881Speter/* 1074251881Speter * tvsub -- 1075251881Speter * Subtract 2 timeval structs: out = out - in. Out is assumed to 1076251881Speter * be >= in. 1077251881Speter */ 1078251881Speterstatic void 1079251881Spetertvsub(out, in) 1080251881Speter struct timeval *out, *in; 1081251881Speter{ 1082251881Speter 1083251881Speter if ((out->tv_usec -= in->tv_usec) < 0) { 1084251881Speter --out->tv_sec; 1085251881Speter out->tv_usec += 1000000; 1086251881Speter } 1087251881Speter out->tv_sec -= in->tv_sec; 1088251881Speter} 1089251881Speter 1090251881Speter/* 1091251881Speter * status -- 1092251881Speter * Print out statistics when SIGINFO is received. 1093362181Sdim */ 1094251881Speter 1095289180Speterstatic void 1096251881Speterstatus(sig) 1097251881Speter int sig __unused; 1098251881Speter{ 1099251881Speter 1100251881Speter siginfo_p = 1; 1101251881Speter} 1102251881Speter 1103251881Speterstatic void 1104251881Spetercheck_status() 1105251881Speter{ 1106251881Speter 1107251881Speter if (siginfo_p) { 1108251881Speter siginfo_p = 0; 1109251881Speter (void)fprintf(stderr, 1110251881Speter "\r%ld/%ld packets received (%.0f%%) %.3f min / %.3f avg / %.3f max\n", 1111251881Speter nreceived, ntransmitted, 1112251881Speter ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0, 1113251881Speter nreceived ? tmin : 0.0, 1114251881Speter nreceived + nrepeats ? tsum / (nreceived + nrepeats) : tsum, 1115251881Speter tmax); 1116251881Speter } 1117251881Speter} 1118251881Speter 1119251881Speter/* 1120251881Speter * finish -- 1121251881Speter * Print out statistics, and give up. 1122251881Speter */ 1123251881Speterstatic void 1124251881Speterfinish() 1125251881Speter{ 1126251881Speter 1127251881Speter struct termios ts; 1128251881Speter 1129251881Speter (void)signal(SIGINT, SIG_IGN); 1130251881Speter (void)signal(SIGALRM, SIG_IGN); 1131251881Speter (void)putchar('\n'); 1132251881Speter (void)fflush(stdout); 1133251881Speter (void)printf("--- %s ping statistics ---\n", hostname); 1134251881Speter (void)printf("%ld packets transmitted, ", ntransmitted); 1135251881Speter (void)printf("%ld packets received, ", nreceived); 1136251881Speter if (nrepeats) 1137251881Speter (void)printf("+%ld duplicates, ", nrepeats); 1138251881Speter if (ntransmitted) { 1139251881Speter if (nreceived > ntransmitted) 1140251881Speter (void)printf("-- somebody's printing up packets!"); 1141251881Speter else 1142251881Speter (void)printf("%d%% packet loss", 1143251881Speter (int)(((ntransmitted - nreceived) * 100) / 1144251881Speter ntransmitted)); 1145251881Speter } 1146251881Speter (void)putchar('\n'); 1147251881Speter if (nreceived && timing) { 1148251881Speter double n = nreceived + nrepeats; 1149251881Speter double avg = tsum / n; 1150251881Speter double vari = tsumsq / n - avg * avg; 1151251881Speter (void)printf( 1152251881Speter "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", 1153251881Speter tmin, avg, tmax, sqrt(vari)); 1154251881Speter } 1155251881Speter if (reset_kerninfo && tcgetattr(STDOUT_FILENO, &ts) != -1) { 1156251881Speter ts.c_lflag &= ~NOKERNINFO; 1157251881Speter tcsetattr(STDOUT_FILENO, TCSANOW, &ts); 1158251881Speter } 1159251881Speter 1160251881Speter if (nreceived) 1161251881Speter exit(0); 1162251881Speter else 1163251881Speter exit(2); 1164251881Speter} 1165251881Speter 1166251881Speter#ifdef notdef 1167251881Speterstatic char *ttab[] = { 1168251881Speter "Echo Reply", /* ip + seq + udata */ 1169251881Speter "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 1170251881Speter "Source Quench", /* IP */ 1171251881Speter "Redirect", /* redirect type, gateway, + IP */ 1172251881Speter "Echo", 1173251881Speter "Time Exceeded", /* transit, frag reassem + IP */ 1174251881Speter "Parameter Problem", /* pointer + IP */ 1175251881Speter "Timestamp", /* id + seq + three timestamps */ 1176251881Speter "Timestamp Reply", /* " */ 1177251881Speter "Info Request", /* id + sq */ 1178251881Speter "Info Reply" /* " */ 1179251881Speter}; 1180251881Speter#endif 1181251881Speter 1182251881Speter/* 1183251881Speter * pr_icmph -- 1184251881Speter * Print a descriptive string about an ICMP header. 1185251881Speter */ 1186251881Speterstatic void 1187251881Speterpr_icmph(icp) 1188251881Speter struct icmp *icp; 1189251881Speter{ 1190251881Speter 1191251881Speter switch(icp->icmp_type) { 1192251881Speter case ICMP_ECHOREPLY: 1193251881Speter (void)printf("Echo Reply\n"); 1194251881Speter /* XXX ID + Seq + Data */ 1195251881Speter break; 1196251881Speter case ICMP_UNREACH: 1197251881Speter switch(icp->icmp_code) { 1198251881Speter case ICMP_UNREACH_NET: 1199251881Speter (void)printf("Destination Net Unreachable\n"); 1200251881Speter break; 1201251881Speter case ICMP_UNREACH_HOST: 1202251881Speter (void)printf("Destination Host Unreachable\n"); 1203251881Speter break; 1204251881Speter case ICMP_UNREACH_PROTOCOL: 1205251881Speter (void)printf("Destination Protocol Unreachable\n"); 1206251881Speter break; 1207251881Speter case ICMP_UNREACH_PORT: 1208251881Speter (void)printf("Destination Port Unreachable\n"); 1209251881Speter break; 1210251881Speter case ICMP_UNREACH_NEEDFRAG: 1211251881Speter (void)printf("frag needed and DF set (MTU %d)\n", 1212251881Speter ntohs(icp->icmp_nextmtu)); 1213251881Speter break; 1214251881Speter case ICMP_UNREACH_SRCFAIL: 1215251881Speter (void)printf("Source Route Failed\n"); 1216251881Speter break; 1217251881Speter case ICMP_UNREACH_FILTER_PROHIB: 1218251881Speter (void)printf("Communication prohibited by filter\n"); 1219251881Speter break; 1220251881Speter default: 1221362181Sdim (void)printf("Dest Unreachable, Bad Code: %d\n", 1222251881Speter icp->icmp_code); 1223251881Speter break; 1224251881Speter } 1225251881Speter /* Print returned IP header information */ 1226251881Speter#ifndef icmp_data 1227251881Speter pr_retip(&icp->icmp_ip); 1228251881Speter#else 1229251881Speter pr_retip((struct ip *)icp->icmp_data); 1230251881Speter#endif 1231251881Speter break; 1232251881Speter case ICMP_SOURCEQUENCH: 1233251881Speter (void)printf("Source Quench\n"); 1234251881Speter#ifndef icmp_data 1235251881Speter pr_retip(&icp->icmp_ip); 1236251881Speter#else 1237251881Speter pr_retip((struct ip *)icp->icmp_data); 1238251881Speter#endif 1239251881Speter break; 1240251881Speter case ICMP_REDIRECT: 1241251881Speter switch(icp->icmp_code) { 1242251881Speter case ICMP_REDIRECT_NET: 1243251881Speter (void)printf("Redirect Network"); 1244251881Speter break; 1245251881Speter case ICMP_REDIRECT_HOST: 1246251881Speter (void)printf("Redirect Host"); 1247251881Speter break; 1248251881Speter case ICMP_REDIRECT_TOSNET: 1249251881Speter (void)printf("Redirect Type of Service and Network"); 1250251881Speter break; 1251251881Speter case ICMP_REDIRECT_TOSHOST: 1252251881Speter (void)printf("Redirect Type of Service and Host"); 1253251881Speter break; 1254251881Speter default: 1255251881Speter (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 1256251881Speter break; 1257251881Speter } 1258251881Speter (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); 1259251881Speter#ifndef icmp_data 1260251881Speter pr_retip(&icp->icmp_ip); 1261251881Speter#else 1262251881Speter pr_retip((struct ip *)icp->icmp_data); 1263251881Speter#endif 1264251881Speter break; 1265251881Speter case ICMP_ECHO: 1266251881Speter (void)printf("Echo Request\n"); 1267251881Speter /* XXX ID + Seq + Data */ 1268251881Speter break; 1269251881Speter case ICMP_TIMXCEED: 1270251881Speter switch(icp->icmp_code) { 1271251881Speter case ICMP_TIMXCEED_INTRANS: 1272251881Speter (void)printf("Time to live exceeded\n"); 1273251881Speter break; 1274251881Speter case ICMP_TIMXCEED_REASS: 1275251881Speter (void)printf("Frag reassembly time exceeded\n"); 1276251881Speter break; 1277251881Speter default: 1278251881Speter (void)printf("Time exceeded, Bad Code: %d\n", 1279251881Speter icp->icmp_code); 1280251881Speter break; 1281251881Speter } 1282251881Speter#ifndef icmp_data 1283251881Speter pr_retip(&icp->icmp_ip); 1284251881Speter#else 1285251881Speter pr_retip((struct ip *)icp->icmp_data); 1286251881Speter#endif 1287251881Speter break; 1288251881Speter case ICMP_PARAMPROB: 1289251881Speter (void)printf("Parameter problem: pointer = 0x%02x\n", 1290251881Speter icp->icmp_hun.ih_pptr); 1291251881Speter#ifndef icmp_data 1292251881Speter pr_retip(&icp->icmp_ip); 1293251881Speter#else 1294251881Speter pr_retip((struct ip *)icp->icmp_data); 1295251881Speter#endif 1296251881Speter break; 1297251881Speter case ICMP_TSTAMP: 1298251881Speter (void)printf("Timestamp\n"); 1299251881Speter /* XXX ID + Seq + 3 timestamps */ 1300251881Speter break; 1301251881Speter case ICMP_TSTAMPREPLY: 1302251881Speter (void)printf("Timestamp Reply\n"); 1303251881Speter /* XXX ID + Seq + 3 timestamps */ 1304251881Speter break; 1305251881Speter case ICMP_IREQ: 1306251881Speter (void)printf("Information Request\n"); 1307251881Speter /* XXX ID + Seq */ 1308251881Speter break; 1309251881Speter case ICMP_IREQREPLY: 1310251881Speter (void)printf("Information Reply\n"); 1311251881Speter /* XXX ID + Seq */ 1312251881Speter break; 1313251881Speter case ICMP_MASKREQ: 1314251881Speter (void)printf("Address Mask Request\n"); 1315251881Speter break; 1316251881Speter case ICMP_MASKREPLY: 1317251881Speter (void)printf("Address Mask Reply\n"); 1318251881Speter break; 1319251881Speter case ICMP_ROUTERADVERT: 1320251881Speter (void)printf("Router Advertisement\n"); 1321251881Speter break; 1322251881Speter case ICMP_ROUTERSOLICIT: 1323251881Speter (void)printf("Router Solicitation\n"); 1324251881Speter break; 1325251881Speter default: 1326251881Speter (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 1327251881Speter } 1328251881Speter} 1329251881Speter 1330251881Speter/* 1331251881Speter * pr_iph -- 1332251881Speter * Print an IP header with options. 1333251881Speter */ 1334251881Speterstatic void 1335251881Speterpr_iph(ip) 1336251881Speter struct ip *ip; 1337251881Speter{ 1338251881Speter u_char *cp; 1339251881Speter int hlen; 1340251881Speter 1341251881Speter hlen = ip->ip_hl << 2; 1342251881Speter cp = (u_char *)ip + 20; /* point to options */ 1343251881Speter 1344251881Speter (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); 1345251881Speter (void)printf(" %1x %1x %02x %04x %04x", 1346251881Speter ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 1347251881Speter ntohs(ip->ip_id)); 1348251881Speter (void)printf(" %1lx %04lx", 1349251881Speter (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13, 1350251881Speter (u_long) ntohl(ip->ip_off) & 0x1fff); 1351251881Speter (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 1352251881Speter ntohs(ip->ip_sum)); 1353251881Speter (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); 1354251881Speter (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); 1355251881Speter /* dump any option bytes */ 1356251881Speter while (hlen-- > 20) { 1357251881Speter (void)printf("%02x", *cp++); 1358251881Speter } 1359251881Speter (void)putchar('\n'); 1360251881Speter} 1361251881Speter 1362251881Speter/* 1363251881Speter * pr_addr -- 1364251881Speter * Return an ascii host address as a dotted quad and optionally with 1365251881Speter * a hostname. 1366251881Speter */ 1367251881Speterstatic char * 1368251881Speterpr_addr(ina) 1369251881Speter struct in_addr ina; 1370251881Speter{ 1371251881Speter struct hostent *hp; 1372251881Speter static char buf[16 + 3 + MAXHOSTNAMELEN]; 1373251881Speter 1374251881Speter if ((options & F_NUMERIC) || 1375251881Speter !(hp = gethostbyaddr((char *)&ina, 4, AF_INET))) 1376251881Speter return inet_ntoa(ina); 1377251881Speter else 1378251881Speter (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 1379251881Speter inet_ntoa(ina)); 1380251881Speter return(buf); 1381251881Speter} 1382251881Speter 1383251881Speter/* 1384251881Speter * pr_retip -- 1385251881Speter * Dump some info on a returned (via ICMP) IP packet. 1386251881Speter */ 1387251881Speterstatic void 1388251881Speterpr_retip(ip) 1389251881Speter struct ip *ip; 1390251881Speter{ 1391251881Speter u_char *cp; 1392251881Speter int hlen; 1393251881Speter 1394251881Speter pr_iph(ip); 1395251881Speter hlen = ip->ip_hl << 2; 1396251881Speter cp = (u_char *)ip + hlen; 1397251881Speter 1398251881Speter if (ip->ip_p == 6) 1399251881Speter (void)printf("TCP: from port %u, to port %u (decimal)\n", 1400251881Speter (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 1401251881Speter else if (ip->ip_p == 17) 1402251881Speter (void)printf("UDP: from port %u, to port %u (decimal)\n", 1403251881Speter (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 1404251881Speter} 1405251881Speter 1406251881Speterstatic void 1407251881Speterfill(bp, patp) 1408251881Speter char *bp, *patp; 1409251881Speter{ 1410251881Speter char *cp; 1411251881Speter int pat[16]; 1412251881Speter u_int ii, jj, kk; 1413251881Speter 1414251881Speter for (cp = patp; *cp; cp++) { 1415251881Speter if (!isxdigit(*cp)) 1416251881Speter errx(EX_USAGE, 1417251881Speter "patterns must be specified as hex digits"); 1418251881Speter 1419251881Speter } 1420251881Speter ii = sscanf(patp, 1421251881Speter "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 1422251881Speter &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 1423251881Speter &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 1424251881Speter &pat[13], &pat[14], &pat[15]); 1425251881Speter 1426251881Speter if (ii > 0) 1427251881Speter for (kk = 0; kk <= MAXPAYLOAD - (PHDR_LEN + ii); kk += ii) 1428251881Speter for (jj = 0; jj < ii; ++jj) 1429251881Speter bp[jj + kk] = pat[jj]; 1430251881Speter if (!(options & F_QUIET)) { 1431251881Speter (void)printf("PATTERN: 0x"); 1432251881Speter for (jj = 0; jj < ii; ++jj) 1433251881Speter (void)printf("%02x", bp[jj] & 0xFF); 1434251881Speter (void)printf("\n"); 1435251881Speter } 1436251881Speter} 1437251881Speter 1438251881Speterstatic void 1439251881Speterusage() 1440251881Speter{ 1441251881Speter (void)fprintf(stderr, "%s\n%s\n%s\n", 1442251881Speter"usage: ping [-AQRadfnqrv] [-c count] [-i wait] [-l preload] [-m ttl]", 1443251881Speter" [-p pattern] " 1444251881Speter#ifdef IPSEC 1445251881Speter#ifdef IPSEC_POLICY_IPSEC 1446251881Speter"[-P policy] " 1447251881Speter#endif 1448251881Speter#endif 1449251881Speter"[-s packetsize] [-S src_addr] [-t timeout]", 1450251881Speter" [host | [-L] [-I iface] [-T ttl] mcast-group]"); 1451251881Speter exit(EX_USAGE); 1452251881Speter} 1453251881Speter