18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 48fae3551SRodney W. Grimes * Copyright (c) 1989, 1993 58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 68fae3551SRodney W. Grimes * 78fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 88fae3551SRodney W. Grimes * Mike Muuss. 98fae3551SRodney W. Grimes * 108fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 118fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 128fae3551SRodney W. Grimes * are met: 138fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 158fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 168fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 178fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 198fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 208fae3551SRodney W. Grimes * without specific prior written permission. 218fae3551SRodney W. Grimes * 228fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 238fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 248fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 258fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 268fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 278fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 288fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 298fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 308fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 318fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 328fae3551SRodney W. Grimes * SUCH DAMAGE. 338fae3551SRodney W. Grimes */ 348fae3551SRodney W. Grimes 358fae3551SRodney W. Grimes /* 368fae3551SRodney W. Grimes * P I N G . C 378fae3551SRodney W. Grimes * 38e345a80dSPhilippe Charnier * Using the Internet Control Message Protocol (ICMP) "ECHO" facility, 398fae3551SRodney W. Grimes * measure round-trip-delays and packet loss across network paths. 408fae3551SRodney W. Grimes * 418fae3551SRodney W. Grimes * Author - 428fae3551SRodney W. Grimes * Mike Muuss 438fae3551SRodney W. Grimes * U. S. Army Ballistic Research Laboratory 448fae3551SRodney W. Grimes * December, 1983 458fae3551SRodney W. Grimes * 468fae3551SRodney W. Grimes * Status - 478fae3551SRodney W. Grimes * Public Domain. Distribution Unlimited. 488fae3551SRodney W. Grimes * Bugs - 498fae3551SRodney W. Grimes * More statistics could always be gathered. 508fae3551SRodney W. Grimes * This program has to run SUID to ROOT to access the ICMP socket. 518fae3551SRodney W. Grimes */ 528fae3551SRodney W. Grimes 5343470e3bSGarrett Wollman #include <sys/param.h> /* NB: we rely on this for <sys/types.h> */ 54b881b8beSRobert Watson #include <sys/capsicum.h> 558fae3551SRodney W. Grimes #include <sys/socket.h> 56261e59bbSMaxim Konovalov #include <sys/sysctl.h> 578fae3551SRodney W. Grimes #include <sys/time.h> 58039d6aa4SBill Fenner #include <sys/uio.h> 598fae3551SRodney W. Grimes 608fae3551SRodney W. Grimes #include <netinet/in.h> 6143470e3bSGarrett Wollman #include <netinet/in_systm.h> 628fae3551SRodney W. Grimes #include <netinet/ip.h> 638fae3551SRodney W. Grimes #include <netinet/ip_icmp.h> 648fae3551SRodney W. Grimes #include <netinet/ip_var.h> 6543470e3bSGarrett Wollman #include <arpa/inet.h> 66c501d73cSMariusz Zaborski 67c501d73cSMariusz Zaborski #include <libcasper.h> 68c501d73cSMariusz Zaborski #include <casper/cap_dns.h> 698fae3551SRodney W. Grimes 709a4365d0SYoshinobu Inoue #ifdef IPSEC 718409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h> 729a4365d0SYoshinobu Inoue #endif /*IPSEC*/ 739a4365d0SYoshinobu Inoue 747bdc3291SMark Johnston #include <capsicum_helpers.h> 75261e59bbSMaxim Konovalov #include <ctype.h> 76261e59bbSMaxim Konovalov #include <err.h> 77261e59bbSMaxim Konovalov #include <errno.h> 78261e59bbSMaxim Konovalov #include <netdb.h> 79d9cacf60SAlan Somers #include <stddef.h> 80261e59bbSMaxim Konovalov #include <signal.h> 81261e59bbSMaxim Konovalov #include <stdio.h> 82261e59bbSMaxim Konovalov #include <stdlib.h> 83261e59bbSMaxim Konovalov #include <string.h> 84261e59bbSMaxim Konovalov #include <sysexits.h> 851ad76f1bSAlan Somers #include <time.h> 86261e59bbSMaxim Konovalov #include <unistd.h> 87261e59bbSMaxim Konovalov 883cde9171SAlan Somers #include "main.h" 893cde9171SAlan Somers #include "ping.h" 90ff77ab83SAlan Somers #include "utils.h" 91ff77ab83SAlan Somers 92301207dfSMaxim Konovalov #define INADDR_LEN ((int)sizeof(in_addr_t)) 9313e3f0b7SMaxim Konovalov #define TIMEVAL_LEN ((int)sizeof(struct tv32)) 94eb1543c6SMatthew N. Dodd #define MASK_LEN (ICMP_MASKLEN - ICMP_MINLEN) 95eb1543c6SMatthew N. Dodd #define TS_LEN (ICMP_TSLEN - ICMP_MINLEN) 96c67c1ce8SMatthew N. Dodd #define DEFDATALEN 56 /* default data length */ 978f975bb3SBruce Evans #define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */ 988f975bb3SBruce Evans /* runs out of buffer space */ 99eaab8826SMark Johnston #define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN) 100eaab8826SMark Johnston #define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN) 101d6cd1497SGleb Smirnoff #define MAXWAIT 10000 /* max ms to wait for response */ 102bf113f1bSBill Fumerola #define MAXALARM (60 * 60) /* max seconds for alarm timeout */ 1030b2f8b3fSMaxim Konovalov #define MAXTOS 255 1048fae3551SRodney W. Grimes 1058fae3551SRodney W. Grimes #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 1068fae3551SRodney W. Grimes #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 1078fae3551SRodney W. Grimes #define SET(bit) (A(bit) |= B(bit)) 1088fae3551SRodney W. Grimes #define CLR(bit) (A(bit) &= (~B(bit))) 1098fae3551SRodney W. Grimes #define TST(bit) (A(bit) & B(bit)) 1108fae3551SRodney W. Grimes 11113e3f0b7SMaxim Konovalov struct tv32 { 11213e3f0b7SMaxim Konovalov int32_t tv32_sec; 1131ad76f1bSAlan Somers int32_t tv32_nsec; 11413e3f0b7SMaxim Konovalov }; 11513e3f0b7SMaxim Konovalov 1168fae3551SRodney W. Grimes /* various options */ 11785456935SBill Fenner #define F_FLOOD 0x0001 11885456935SBill Fenner #define F_INTERVAL 0x0002 11985456935SBill Fenner #define F_PINGFILLED 0x0008 12085456935SBill Fenner #define F_QUIET 0x0010 12185456935SBill Fenner #define F_RROUTE 0x0020 12285456935SBill Fenner #define F_SO_DEBUG 0x0040 12385456935SBill Fenner #define F_SO_DONTROUTE 0x0080 12485456935SBill Fenner #define F_VERBOSE 0x0100 12585456935SBill Fenner #define F_QUIET2 0x0200 12685456935SBill Fenner #define F_NOLOOP 0x0400 12785456935SBill Fenner #define F_MTTL 0x0800 12885456935SBill Fenner #define F_MIF 0x1000 129772dfa72SDaniel O'Callaghan #define F_AUDIBLE 0x2000 1309a4365d0SYoshinobu Inoue #ifdef IPSEC 1319a4365d0SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC 1329a4365d0SYoshinobu Inoue #define F_POLICY 0x4000 1339a4365d0SYoshinobu Inoue #endif /*IPSEC_POLICY_IPSEC*/ 1349a4365d0SYoshinobu Inoue #endif /*IPSEC*/ 135211bfbd2SRuslan Ermilov #define F_TTL 0x8000 136ca517ad8SPoul-Henning Kamp #define F_MISSED 0x10000 1378025c44bSDima Dorfman #define F_ONCE 0x20000 1380b2f8b3fSMaxim Konovalov #define F_HDRINCL 0x40000 139143008a1SMatthew N. Dodd #define F_MASK 0x80000 140eb1543c6SMatthew N. Dodd #define F_TIME 0x100000 1419ff95228SGleb Smirnoff #define F_SWEEP 0x200000 142d6cd1497SGleb Smirnoff #define F_WAITTIME 0x400000 14381a6f4c7SRichard Scheffenegger #define F_IP_VLAN_PCP 0x800000 144d399eb3eSPiotr Pawel Stefaniak #define F_DOT 0x1000000 1458fae3551SRodney W. Grimes 1468fae3551SRodney W. Grimes /* 1478fae3551SRodney W. Grimes * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 1488fae3551SRodney W. Grimes * number of received sequence numbers we can keep track of. Change 128 1498fae3551SRodney W. Grimes * to 8192 for complete accuracy... 1508fae3551SRodney W. Grimes */ 1518fae3551SRodney W. Grimes #define MAX_DUP_CHK (8 * 128) 1527e9489e0SHiroki Sato static int mx_dup_ck = MAX_DUP_CHK; 1537e9489e0SHiroki Sato static char rcvd_tbl[MAX_DUP_CHK / 8]; 1548fae3551SRodney W. Grimes 1557e9489e0SHiroki Sato static struct sockaddr_in whereto; /* who to ping */ 1567e9489e0SHiroki Sato static int datalen = DEFDATALEN; 1577e9489e0SHiroki Sato static int maxpayload; 1587e9489e0SHiroki Sato static int ssend; /* send socket file descriptor */ 1597e9489e0SHiroki Sato static int srecv; /* receive socket file descriptor */ 1607e9489e0SHiroki Sato static u_char outpackhdr[IP_MAXPACKET], *outpack; 1617e9489e0SHiroki Sato static char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ 1627e9489e0SHiroki Sato static char BSPACE = '\b'; /* characters written for flood */ 163d399eb3eSPiotr Pawel Stefaniak static const char *DOT = "."; 164d399eb3eSPiotr Pawel Stefaniak static size_t DOTlen = 1; 165d399eb3eSPiotr Pawel Stefaniak static size_t DOTidx = 0; 1667e9489e0SHiroki Sato static char *shostname; 1677e9489e0SHiroki Sato static int ident; /* process id to identify our packets */ 1687e9489e0SHiroki Sato static int uid; /* cached uid for micro-optimization */ 1697e9489e0SHiroki Sato static u_char icmp_type = ICMP_ECHO; 1707e9489e0SHiroki Sato static u_char icmp_type_rsp = ICMP_ECHOREPLY; 1717e9489e0SHiroki Sato static int phdr_len = 0; 1727e9489e0SHiroki Sato static int send_len; 1738fae3551SRodney W. Grimes 1748fae3551SRodney W. Grimes /* counters */ 1757e9489e0SHiroki Sato static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 1767e9489e0SHiroki Sato static long npackets; /* max packets to transmit */ 1777e9489e0SHiroki Sato static long snpackets; /* max packets to transmit in one sweep */ 1787e9489e0SHiroki Sato static long sntransmitted; /* # of packets we sent in this sweep */ 1797e9489e0SHiroki Sato static int sweepmax; /* max value of payload in sweep */ 1807e9489e0SHiroki Sato static int sweepmin = 0; /* start value of payload in sweep */ 1817e9489e0SHiroki Sato static int sweepincr = 1; /* payload increment in sweep */ 1827e9489e0SHiroki Sato static int interval = 1000; /* interval between packets, ms */ 1837e9489e0SHiroki Sato static int waittime = MAXWAIT; /* timeout for each packet */ 184badd8138SSean Eric Fagan 18549133c6dSPawel Jakub Dawidek static cap_channel_t *capdns; 18649133c6dSPawel Jakub Dawidek 18743470e3bSGarrett Wollman static void fill(char *, char *); 18849133c6dSPawel Jakub Dawidek static cap_channel_t *capdns_setup(void); 18943470e3bSGarrett Wollman static void pinger(void); 19043470e3bSGarrett Wollman static char *pr_addr(struct in_addr); 191eb1543c6SMatthew N. Dodd static char *pr_ntime(n_time); 192d9cacf60SAlan Somers static void pr_icmph(struct icmp *, struct ip *, const u_char *const); 19320b41303SJose Luis Duran static void pr_iph(struct ip *, const u_char *); 194d9cacf60SAlan Somers static void pr_pack(char *, ssize_t, struct sockaddr_in *, struct timespec *); 1958fae3551SRodney W. Grimes 19643470e3bSGarrett Wollman int 1973cde9171SAlan Somers ping(int argc, char *const *argv) 1988fae3551SRodney W. Grimes { 19931eac03bSSean Chittenden struct sockaddr_in from, sock_in; 200efc8588dSDavid E. O'Brien struct in_addr ifaddr; 2011ad76f1bSAlan Somers struct timespec last, intvl; 202efc8588dSDavid E. O'Brien struct iovec iov; 203efc8588dSDavid E. O'Brien struct msghdr msg; 204efc8588dSDavid E. O'Brien struct sigaction si_sa; 2050b2f8b3fSMaxim Konovalov size_t sz; 206e81f5049SOlivier Houchard u_char *datap, packet[IP_MAXPACKET] __aligned(4); 20778e1f68eSMark Johnston const char *errstr; 208d074d39fSMatthew N. Dodd char *ep, *source, *target, *payload; 209261e59bbSMaxim Konovalov struct hostent *hp; 210efc8588dSDavid E. O'Brien #ifdef IPSEC_POLICY_IPSEC 211efc8588dSDavid E. O'Brien char *policy_in, *policy_out; 212efc8588dSDavid E. O'Brien #endif 213261e59bbSMaxim Konovalov struct sockaddr_in *to; 214261e59bbSMaxim Konovalov double t; 215c0a3773aSEugene Grosbein u_long alarmtimeout; 21678e1f68eSMark Johnston long long ltmp; 21749133c6dSPawel Jakub Dawidek int almost_done, ch, df, hold, i, icmp_len, mib[4], preload; 21881a6f4c7SRichard Scheffenegger int ssend_errno, srecv_errno, tos, ttl, pcp; 2191ad76f1bSAlan Somers char ctrl[CMSG_SPACE(sizeof(struct timespec))]; 220efc8588dSDavid E. O'Brien char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; 2218fae3551SRodney W. Grimes #ifdef IP_OPTIONS 2224fba6582SMaxim Konovalov char rspace[MAX_IPOPTLEN]; /* record route space */ 2238fae3551SRodney W. Grimes #endif 224261e59bbSMaxim Konovalov unsigned char loop, mttl; 225efc8588dSDavid E. O'Brien 22631eac03bSSean Chittenden payload = source = NULL; 2279a4365d0SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC 228efc8588dSDavid E. O'Brien policy_in = policy_out = NULL; 2299a4365d0SYoshinobu Inoue #endif 23049133c6dSPawel Jakub Dawidek cap_rights_t rights; 2318fae3551SRodney W. Grimes 232f1284d7aSBill Fenner /* 233f1284d7aSBill Fenner * Do the stuff that we need root priv's for *first*, and 234f1284d7aSBill Fenner * then drop our setuid bit. Save error reporting for 235f1284d7aSBill Fenner * after arg parsing. 23649133c6dSPawel Jakub Dawidek * 23749133c6dSPawel Jakub Dawidek * Historicaly ping was using one socket 's' for sending and for 23849133c6dSPawel Jakub Dawidek * receiving. After capsicum(4) related changes we use two 23949133c6dSPawel Jakub Dawidek * sockets. It was done for special ping use case - when user 24049133c6dSPawel Jakub Dawidek * issue ping on multicast or broadcast address replies come 24149133c6dSPawel Jakub Dawidek * from different addresses, not from the address we 24249133c6dSPawel Jakub Dawidek * connect(2)'ed to, and send socket do not receive those 24349133c6dSPawel Jakub Dawidek * packets. 244f1284d7aSBill Fenner */ 24549133c6dSPawel Jakub Dawidek ssend = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 24649133c6dSPawel Jakub Dawidek ssend_errno = errno; 24749133c6dSPawel Jakub Dawidek srecv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 24849133c6dSPawel Jakub Dawidek srecv_errno = errno; 249f1284d7aSBill Fenner 2501d1d4a47SEitan Adler if (setuid(getuid()) != 0) 2511d1d4a47SEitan Adler err(EX_NOPERM, "setuid() failed"); 252ee2bf734SWarner Losh uid = getuid(); 253f1284d7aSBill Fenner 254eeb63943SDon Lewis if (ssend < 0) { 255eeb63943SDon Lewis errno = ssend_errno; 256eeb63943SDon Lewis err(EX_OSERR, "ssend socket"); 257eeb63943SDon Lewis } 258eeb63943SDon Lewis 259eeb63943SDon Lewis if (srecv < 0) { 260eeb63943SDon Lewis errno = srecv_errno; 261eeb63943SDon Lewis err(EX_OSERR, "srecv socket"); 262eeb63943SDon Lewis } 263eeb63943SDon Lewis 26481a6f4c7SRichard Scheffenegger alarmtimeout = df = preload = tos = pcp = 0; 265badd8138SSean Eric Fagan 2660b2f8b3fSMaxim Konovalov outpack = outpackhdr + sizeof(struct ip); 2679ce201f2SAlan Somers while ((ch = getopt(argc, argv, PING4OPTS)) != -1) { 2688fae3551SRodney W. Grimes switch(ch) { 269d399eb3eSPiotr Pawel Stefaniak case '.': 270d399eb3eSPiotr Pawel Stefaniak options |= F_DOT; 271d399eb3eSPiotr Pawel Stefaniak if (optarg != NULL) { 272d399eb3eSPiotr Pawel Stefaniak DOT = optarg; 273d399eb3eSPiotr Pawel Stefaniak DOTlen = strlen(optarg); 274d399eb3eSPiotr Pawel Stefaniak } 275d399eb3eSPiotr Pawel Stefaniak break; 2763cde9171SAlan Somers case '4': 2773cde9171SAlan Somers /* This option is processed in main(). */ 2783cde9171SAlan Somers break; 279ca517ad8SPoul-Henning Kamp case 'A': 280ca517ad8SPoul-Henning Kamp options |= F_MISSED; 281ca517ad8SPoul-Henning Kamp break; 282772dfa72SDaniel O'Callaghan case 'a': 283772dfa72SDaniel O'Callaghan options |= F_AUDIBLE; 284772dfa72SDaniel O'Callaghan break; 28581a6f4c7SRichard Scheffenegger case 'C': 28681a6f4c7SRichard Scheffenegger options |= F_IP_VLAN_PCP; 28778e1f68eSMark Johnston ltmp = strtonum(optarg, -1, 7, &errstr); 28878e1f68eSMark Johnston if (errstr != NULL) 28981a6f4c7SRichard Scheffenegger errx(EX_USAGE, "invalid PCP: `%s'", optarg); 29081a6f4c7SRichard Scheffenegger pcp = ltmp; 29181a6f4c7SRichard Scheffenegger break; 2928fae3551SRodney W. Grimes case 'c': 29378e1f68eSMark Johnston ltmp = strtonum(optarg, 1, LONG_MAX, &errstr); 29478e1f68eSMark Johnston if (errstr != NULL) 29543470e3bSGarrett Wollman errx(EX_USAGE, 29643470e3bSGarrett Wollman "invalid count of packets to transmit: `%s'", 29743470e3bSGarrett Wollman optarg); 29878e1f68eSMark Johnston npackets = (long)ltmp; 2998fae3551SRodney W. Grimes break; 3000b2f8b3fSMaxim Konovalov case 'D': 3010b2f8b3fSMaxim Konovalov options |= F_HDRINCL; 3020b2f8b3fSMaxim Konovalov df = 1; 3030b2f8b3fSMaxim Konovalov break; 3048fae3551SRodney W. Grimes case 'd': 3058fae3551SRodney W. Grimes options |= F_SO_DEBUG; 3068fae3551SRodney W. Grimes break; 3078fae3551SRodney W. Grimes case 'f': 308526f06b2SMatthew Dillon if (uid) { 30943470e3bSGarrett Wollman errno = EPERM; 31043470e3bSGarrett Wollman err(EX_NOPERM, "-f flag"); 3118fae3551SRodney W. Grimes } 3128fae3551SRodney W. Grimes options |= F_FLOOD; 313d399eb3eSPiotr Pawel Stefaniak options |= F_DOT; 3148fae3551SRodney W. Grimes setbuf(stdout, (char *)NULL); 3158fae3551SRodney W. Grimes break; 316*8408510cSMaxim Konovalov case 'G': /* Maximum payload size for ping sweep */ 31778e1f68eSMark Johnston ltmp = strtonum(optarg, 1, INT_MAX, &errstr); 31878e1f68eSMark Johnston if (errstr != NULL) { 319*8408510cSMaxim Konovalov errx(EX_USAGE, "invalid payload size: `%s'", 3209ff95228SGleb Smirnoff optarg); 32178e1f68eSMark Johnston } 32278e1f68eSMark Johnston sweepmax = (int)ltmp; 32378e1f68eSMark Johnston if (uid != 0 && sweepmax > DEFDATALEN) { 32478e1f68eSMark Johnston errc(EX_NOPERM, EPERM, 325*8408510cSMaxim Konovalov "payload size too large: %d > %u", 32678e1f68eSMark Johnston sweepmax, DEFDATALEN); 3279ff95228SGleb Smirnoff } 3289ff95228SGleb Smirnoff options |= F_SWEEP; 3299ff95228SGleb Smirnoff break; 330*8408510cSMaxim Konovalov case 'g': /* Minimum payload size for ping sweep */ 33139d3c81cSMaxim Konovalov ltmp = strtonum(optarg, 0, INT_MAX, &errstr); 33278e1f68eSMark Johnston if (errstr != NULL) { 333*8408510cSMaxim Konovalov errx(EX_USAGE, "invalid payload size: `%s'", 3349ff95228SGleb Smirnoff optarg); 33578e1f68eSMark Johnston } 33678e1f68eSMark Johnston sweepmin = (int)ltmp; 33778e1f68eSMark Johnston if (uid != 0 && sweepmin > DEFDATALEN) { 33878e1f68eSMark Johnston errc(EX_NOPERM, EPERM, 339*8408510cSMaxim Konovalov "payload size too large: %d > %u", 34078e1f68eSMark Johnston sweepmin, DEFDATALEN); 3419ff95228SGleb Smirnoff } 3429ff95228SGleb Smirnoff options |= F_SWEEP; 3439ff95228SGleb Smirnoff break; 34499f13ae1SAlan Somers case 'H': 34503d4d1c7SJose Luis Duran options |= F_HOSTNAME; 34699f13ae1SAlan Somers break; 347*8408510cSMaxim Konovalov case 'h': /* Payload size increment for ping sweep */ 34878e1f68eSMark Johnston ltmp = strtonum(optarg, 1, INT_MAX, &errstr); 34978e1f68eSMark Johnston if (errstr != NULL) { 350*8408510cSMaxim Konovalov errx(EX_USAGE, "invalid payload size: `%s'", 3519ff95228SGleb Smirnoff optarg); 35278e1f68eSMark Johnston } 35378e1f68eSMark Johnston sweepincr = (int)ltmp; 35478e1f68eSMark Johnston if (uid != 0 && sweepincr > DEFDATALEN) { 35578e1f68eSMark Johnston errc(EX_NOPERM, EPERM, 356*8408510cSMaxim Konovalov "payload size too large: %d > %u", 35778e1f68eSMark Johnston sweepincr, DEFDATALEN); 3589ff95228SGleb Smirnoff } 3599ff95228SGleb Smirnoff options |= F_SWEEP; 3609ff95228SGleb Smirnoff break; 3611f6a4631SRuslan Ermilov case 'I': /* multicast interface */ 3621f6a4631SRuslan Ermilov if (inet_aton(optarg, &ifaddr) == 0) 3631f6a4631SRuslan Ermilov errx(EX_USAGE, 3641f6a4631SRuslan Ermilov "invalid multicast interface: `%s'", 3651f6a4631SRuslan Ermilov optarg); 3661f6a4631SRuslan Ermilov options |= F_MIF; 3671f6a4631SRuslan Ermilov break; 3688fae3551SRodney W. Grimes case 'i': /* wait between sending packets */ 3691ad0b1beSMaxim Konovalov t = strtod(optarg, &ep) * 1000.0; 3701ad0b1beSMaxim Konovalov if (*ep || ep == optarg || t > (double)INT_MAX) 3711ad0b1beSMaxim Konovalov errx(EX_USAGE, "invalid timing interval: `%s'", 3721ad0b1beSMaxim Konovalov optarg); 3738fae3551SRodney W. Grimes options |= F_INTERVAL; 374526f06b2SMatthew Dillon interval = (int)t; 375526f06b2SMatthew Dillon if (uid && interval < 1000) { 376526f06b2SMatthew Dillon errno = EPERM; 377526f06b2SMatthew Dillon err(EX_NOPERM, "-i interval too short"); 378526f06b2SMatthew Dillon } 3798fae3551SRodney W. Grimes break; 3801f6a4631SRuslan Ermilov case 'L': 3811f6a4631SRuslan Ermilov options |= F_NOLOOP; 3821f6a4631SRuslan Ermilov loop = 0; 38385456935SBill Fenner break; 3848fae3551SRodney W. Grimes case 'l': 38578e1f68eSMark Johnston ltmp = strtonum(optarg, 0, INT_MAX, &errstr); 38678e1f68eSMark Johnston if (errstr != NULL) 38743470e3bSGarrett Wollman errx(EX_USAGE, 38843470e3bSGarrett Wollman "invalid preload value: `%s'", optarg); 3895e2cc0f4SStephen McKay if (uid) { 390f78ac61bSWarner Losh errno = EPERM; 391f78ac61bSWarner Losh err(EX_NOPERM, "-l flag"); 392f78ac61bSWarner Losh } 39378e1f68eSMark Johnston preload = (int)ltmp; 3948fae3551SRodney W. Grimes break; 3951f6a4631SRuslan Ermilov case 'M': 396eb1543c6SMatthew N. Dodd switch(optarg[0]) { 397eb1543c6SMatthew N. Dodd case 'M': 398eb1543c6SMatthew N. Dodd case 'm': 3991f6a4631SRuslan Ermilov options |= F_MASK; 40085456935SBill Fenner break; 401eb1543c6SMatthew N. Dodd case 'T': 402eb1543c6SMatthew N. Dodd case 't': 403eb1543c6SMatthew N. Dodd options |= F_TIME; 404eb1543c6SMatthew N. Dodd break; 405eb1543c6SMatthew N. Dodd default: 406eb1543c6SMatthew N. Dodd errx(EX_USAGE, "invalid message: `%c'", optarg[0]); 407eb1543c6SMatthew N. Dodd break; 408eb1543c6SMatthew N. Dodd } 409eb1543c6SMatthew N. Dodd break; 410211bfbd2SRuslan Ermilov case 'm': /* TTL */ 41178e1f68eSMark Johnston ltmp = strtonum(optarg, 0, MAXTTL, &errstr); 41278e1f68eSMark Johnston if (errstr != NULL) 4131ad0b1beSMaxim Konovalov errx(EX_USAGE, "invalid TTL: `%s'", optarg); 41478e1f68eSMark Johnston ttl = (int)ltmp; 415211bfbd2SRuslan Ermilov options |= F_TTL; 416211bfbd2SRuslan Ermilov break; 4178fae3551SRodney W. Grimes case 'n': 41803d4d1c7SJose Luis Duran options &= ~F_HOSTNAME; 4198fae3551SRodney W. Grimes break; 4208025c44bSDima Dorfman case 'o': 4218025c44bSDima Dorfman options |= F_ONCE; 4228025c44bSDima Dorfman break; 4231f6a4631SRuslan Ermilov #ifdef IPSEC 4241f6a4631SRuslan Ermilov #ifdef IPSEC_POLICY_IPSEC 4251f6a4631SRuslan Ermilov case 'P': 4261f6a4631SRuslan Ermilov options |= F_POLICY; 4271f6a4631SRuslan Ermilov if (!strncmp("in", optarg, 2)) 4281f6a4631SRuslan Ermilov policy_in = strdup(optarg); 4291f6a4631SRuslan Ermilov else if (!strncmp("out", optarg, 3)) 4301f6a4631SRuslan Ermilov policy_out = strdup(optarg); 4311f6a4631SRuslan Ermilov else 4321f6a4631SRuslan Ermilov errx(1, "invalid security policy"); 4331f6a4631SRuslan Ermilov break; 4341f6a4631SRuslan Ermilov #endif /*IPSEC_POLICY_IPSEC*/ 4351f6a4631SRuslan Ermilov #endif /*IPSEC*/ 4368fae3551SRodney W. Grimes case 'p': /* fill buffer with user pattern */ 4378fae3551SRodney W. Grimes options |= F_PINGFILLED; 438d074d39fSMatthew N. Dodd payload = optarg; 4398fae3551SRodney W. Grimes break; 440ef9e6dc7SBill Fenner case 'Q': 441ef9e6dc7SBill Fenner options |= F_QUIET2; 442ef9e6dc7SBill Fenner break; 4438fae3551SRodney W. Grimes case 'q': 4448fae3551SRodney W. Grimes options |= F_QUIET; 4458fae3551SRodney W. Grimes break; 4468fae3551SRodney W. Grimes case 'R': 4478fae3551SRodney W. Grimes options |= F_RROUTE; 4488fae3551SRodney W. Grimes break; 4498fae3551SRodney W. Grimes case 'r': 4508fae3551SRodney W. Grimes options |= F_SO_DONTROUTE; 4518fae3551SRodney W. Grimes break; 4521f6a4631SRuslan Ermilov case 'S': 4531f6a4631SRuslan Ermilov source = optarg; 4541f6a4631SRuslan Ermilov break; 4558fae3551SRodney W. Grimes case 's': /* size of packet to send */ 45678e1f68eSMark Johnston ltmp = strtonum(optarg, 0, INT_MAX, &errstr); 45778e1f68eSMark Johnston if (errstr != NULL) 45843470e3bSGarrett Wollman errx(EX_USAGE, "invalid packet size: `%s'", 45943470e3bSGarrett Wollman optarg); 46078e1f68eSMark Johnston datalen = (int)ltmp; 461eaab8826SMark Johnston if (uid != 0 && datalen > DEFDATALEN) { 462eaab8826SMark Johnston errno = EPERM; 463eaab8826SMark Johnston err(EX_NOPERM, 46478e1f68eSMark Johnston "packet size too large: %d > %u", 465eaab8826SMark Johnston datalen, DEFDATALEN); 466fb7d32c7SMaxim Konovalov } 4678fae3551SRodney W. Grimes break; 4681f6a4631SRuslan Ermilov case 'T': /* multicast TTL */ 46978e1f68eSMark Johnston ltmp = strtonum(optarg, 0, MAXTTL, &errstr); 47078e1f68eSMark Johnston if (errstr != NULL) 4711f6a4631SRuslan Ermilov errx(EX_USAGE, "invalid multicast TTL: `%s'", 4721f6a4631SRuslan Ermilov optarg); 47378e1f68eSMark Johnston mttl = (unsigned char)ltmp; 4741f6a4631SRuslan Ermilov options |= F_MTTL; 47599490edeSWarner Losh break; 4767237fd94SBill Fumerola case 't': 477bf113f1bSBill Fumerola alarmtimeout = strtoul(optarg, &ep, 0); 478bf113f1bSBill Fumerola if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) 4797237fd94SBill Fumerola errx(EX_USAGE, "invalid timeout: `%s'", 4807237fd94SBill Fumerola optarg); 481bf113f1bSBill Fumerola if (alarmtimeout > MAXALARM) 482bf113f1bSBill Fumerola errx(EX_USAGE, "invalid timeout: `%s' > %d", 483bf113f1bSBill Fumerola optarg, MAXALARM); 4842eb6acc2SAlan Somers { 4852eb6acc2SAlan Somers struct itimerval itv; 4862eb6acc2SAlan Somers 4872eb6acc2SAlan Somers timerclear(&itv.it_interval); 4882eb6acc2SAlan Somers timerclear(&itv.it_value); 4892eb6acc2SAlan Somers itv.it_value.tv_sec = (time_t)alarmtimeout; 4902eb6acc2SAlan Somers if (setitimer(ITIMER_REAL, &itv, NULL) != 0) 4912eb6acc2SAlan Somers err(1, "setitimer"); 4922eb6acc2SAlan Somers } 4937237fd94SBill Fumerola break; 4948fae3551SRodney W. Grimes case 'v': 4958fae3551SRodney W. Grimes options |= F_VERBOSE; 4968fae3551SRodney W. Grimes break; 497d6cd1497SGleb Smirnoff case 'W': /* wait ms for answer */ 498d6cd1497SGleb Smirnoff t = strtod(optarg, &ep); 499d6cd1497SGleb Smirnoff if (*ep || ep == optarg || t > (double)INT_MAX) 500d6cd1497SGleb Smirnoff errx(EX_USAGE, "invalid timing interval: `%s'", 501d6cd1497SGleb Smirnoff optarg); 502d6cd1497SGleb Smirnoff options |= F_WAITTIME; 503d6cd1497SGleb Smirnoff waittime = (int)t; 504d6cd1497SGleb Smirnoff break; 5050b2f8b3fSMaxim Konovalov case 'z': 5060b2f8b3fSMaxim Konovalov options |= F_HDRINCL; 507c0a3773aSEugene Grosbein ltmp = strtol(optarg, &ep, 0); 508c0a3773aSEugene Grosbein if (*ep || ep == optarg || ltmp > MAXTOS || ltmp < 0) 5090b2f8b3fSMaxim Konovalov errx(EX_USAGE, "invalid TOS: `%s'", optarg); 510c0a3773aSEugene Grosbein tos = ltmp; 5110b2f8b3fSMaxim Konovalov break; 5128fae3551SRodney W. Grimes default: 513e345a80dSPhilippe Charnier usage(); 51443470e3bSGarrett Wollman } 51543470e3bSGarrett Wollman } 51643470e3bSGarrett Wollman 51743470e3bSGarrett Wollman if (argc - optind != 1) 518e345a80dSPhilippe Charnier usage(); 51943470e3bSGarrett Wollman target = argv[optind]; 5208fae3551SRodney W. Grimes 521d829c3dfSMatthew N. Dodd switch (options & (F_MASK|F_TIME)) { 522d829c3dfSMatthew N. Dodd case 0: break; 523d829c3dfSMatthew N. Dodd case F_MASK: 524eb1543c6SMatthew N. Dodd icmp_type = ICMP_MASKREQ; 525eb1543c6SMatthew N. Dodd icmp_type_rsp = ICMP_MASKREPLY; 526d829c3dfSMatthew N. Dodd phdr_len = MASK_LEN; 527eb1543c6SMatthew N. Dodd if (!(options & F_QUIET)) 528eb1543c6SMatthew N. Dodd (void)printf("ICMP_MASKREQ\n"); 529d829c3dfSMatthew N. Dodd break; 530d829c3dfSMatthew N. Dodd case F_TIME: 531eb1543c6SMatthew N. Dodd icmp_type = ICMP_TSTAMP; 532eb1543c6SMatthew N. Dodd icmp_type_rsp = ICMP_TSTAMPREPLY; 533d829c3dfSMatthew N. Dodd phdr_len = TS_LEN; 534eb1543c6SMatthew N. Dodd if (!(options & F_QUIET)) 535eb1543c6SMatthew N. Dodd (void)printf("ICMP_TSTAMP\n"); 536d829c3dfSMatthew N. Dodd break; 537d829c3dfSMatthew N. Dodd default: 538d829c3dfSMatthew N. Dodd errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive."); 539d829c3dfSMatthew N. Dodd break; 540eb1543c6SMatthew N. Dodd } 5410fe0c0ccSMaxim Konovalov icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len; 542fb7d32c7SMaxim Konovalov if (options & F_RROUTE) 543e88178ddSMaxim Konovalov icmp_len += MAX_IPOPTLEN; 544e88178ddSMaxim Konovalov maxpayload = IP_MAXPACKET - icmp_len; 545fb7d32c7SMaxim Konovalov if (datalen > maxpayload) 5461104dd84SBruce Evans errx(EX_USAGE, "packet size too large: %d > %d", datalen, 547fb7d32c7SMaxim Konovalov maxpayload); 548e88178ddSMaxim Konovalov send_len = icmp_len + datalen; 5490fe0c0ccSMaxim Konovalov datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN]; 550d074d39fSMatthew N. Dodd if (options & F_PINGFILLED) { 551d074d39fSMatthew N. Dodd fill((char *)datap, payload); 552d074d39fSMatthew N. Dodd } 55349133c6dSPawel Jakub Dawidek capdns = capdns_setup(); 55499490edeSWarner Losh if (source) { 55531eac03bSSean Chittenden bzero((char *)&sock_in, sizeof(sock_in)); 55631eac03bSSean Chittenden sock_in.sin_family = AF_INET; 55731eac03bSSean Chittenden if (inet_aton(source, &sock_in.sin_addr) != 0) { 55899490edeSWarner Losh shostname = source; 55999490edeSWarner Losh } else { 560d68e2c04SMariusz Zaborski hp = cap_gethostbyname2(capdns, source, AF_INET); 56199490edeSWarner Losh if (!hp) 56299490edeSWarner Losh errx(EX_NOHOST, "cannot resolve %s: %s", 56399490edeSWarner Losh source, hstrerror(h_errno)); 56499490edeSWarner Losh 56531eac03bSSean Chittenden sock_in.sin_len = sizeof sock_in; 56631eac03bSSean Chittenden if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) || 5674fba6582SMaxim Konovalov hp->h_length < 0) 56899490edeSWarner Losh errx(1, "gethostbyname2: illegal address"); 56931eac03bSSean Chittenden memcpy(&sock_in.sin_addr, hp->h_addr_list[0], 57031eac03bSSean Chittenden sizeof(sock_in.sin_addr)); 57199490edeSWarner Losh (void)strncpy(snamebuf, hp->h_name, 57299490edeSWarner Losh sizeof(snamebuf) - 1); 57399490edeSWarner Losh snamebuf[sizeof(snamebuf) - 1] = '\0'; 57499490edeSWarner Losh shostname = snamebuf; 57599490edeSWarner Losh } 57649133c6dSPawel Jakub Dawidek if (bind(ssend, (struct sockaddr *)&sock_in, sizeof sock_in) == 57749133c6dSPawel Jakub Dawidek -1) 57899490edeSWarner Losh err(1, "bind"); 57999490edeSWarner Losh } 58099490edeSWarner Losh 581d389e86aSMatt Jacob bzero(&whereto, sizeof(whereto)); 582d389e86aSMatt Jacob to = &whereto; 5838fae3551SRodney W. Grimes to->sin_family = AF_INET; 584d389e86aSMatt Jacob to->sin_len = sizeof *to; 58543470e3bSGarrett Wollman if (inet_aton(target, &to->sin_addr) != 0) { 5868fae3551SRodney W. Grimes hostname = target; 58743470e3bSGarrett Wollman } else { 58849133c6dSPawel Jakub Dawidek hp = cap_gethostbyname2(capdns, target, AF_INET); 58943470e3bSGarrett Wollman if (!hp) 59043470e3bSGarrett Wollman errx(EX_NOHOST, "cannot resolve %s: %s", 59143470e3bSGarrett Wollman target, hstrerror(h_errno)); 59243470e3bSGarrett Wollman 59331eac03bSSean Chittenden if ((unsigned)hp->h_length > sizeof(to->sin_addr)) 5941ffae4a6SWarner Losh errx(1, "gethostbyname2 returned an illegal address"); 59543470e3bSGarrett Wollman memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr); 5968fae3551SRodney W. Grimes (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 597b10d9d5fSWarner Losh hnamebuf[sizeof(hnamebuf) - 1] = '\0'; 5988fae3551SRodney W. Grimes hostname = hnamebuf; 5998fae3551SRodney W. Grimes } 6008fae3551SRodney W. Grimes 60149133c6dSPawel Jakub Dawidek /* From now on we will use only reverse DNS lookups. */ 602a3ce7698SAlan Somers #ifdef WITH_CASPER 60349133c6dSPawel Jakub Dawidek if (capdns != NULL) { 60449133c6dSPawel Jakub Dawidek const char *types[1]; 60549133c6dSPawel Jakub Dawidek 606752d135eSMariusz Zaborski types[0] = "ADDR2NAME"; 60749133c6dSPawel Jakub Dawidek if (cap_dns_type_limit(capdns, types, 1) < 0) 60849133c6dSPawel Jakub Dawidek err(1, "unable to limit access to system.dns service"); 60949133c6dSPawel Jakub Dawidek } 610a3ce7698SAlan Somers #endif 61149133c6dSPawel Jakub Dawidek if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0) 61249133c6dSPawel Jakub Dawidek err(1, "connect"); 61349133c6dSPawel Jakub Dawidek 61443470e3bSGarrett Wollman if (options & F_FLOOD && options & F_INTERVAL) 61543470e3bSGarrett Wollman errx(EX_USAGE, "-f and -i: incompatible options"); 61643470e3bSGarrett Wollman 61743470e3bSGarrett Wollman if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 61843470e3bSGarrett Wollman errx(EX_USAGE, 61943470e3bSGarrett Wollman "-f flag cannot be used with multicast destination"); 62043470e3bSGarrett Wollman if (options & (F_MIF | F_NOLOOP | F_MTTL) 62143470e3bSGarrett Wollman && !IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 62243470e3bSGarrett Wollman errx(EX_USAGE, 62343470e3bSGarrett Wollman "-I, -L, -T flags cannot be used with unicast destination"); 6248fae3551SRodney W. Grimes 625d829c3dfSMatthew N. Dodd if (datalen >= TIMEVAL_LEN) /* can we time transfer */ 6268fae3551SRodney W. Grimes timing = 1; 62743470e3bSGarrett Wollman 62878e1f68eSMark Johnston if ((options & (F_PINGFILLED | F_SWEEP)) == 0) 629d829c3dfSMatthew N. Dodd for (i = TIMEVAL_LEN; i < datalen; ++i) 6308fae3551SRodney W. Grimes *datap++ = i; 6318fae3551SRodney W. Grimes 6328fae3551SRodney W. Grimes ident = getpid() & 0xFFFF; 6338fae3551SRodney W. Grimes 6348fae3551SRodney W. Grimes hold = 1; 63549133c6dSPawel Jakub Dawidek if (options & F_SO_DEBUG) { 63649133c6dSPawel Jakub Dawidek (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold, 6378fae3551SRodney W. Grimes sizeof(hold)); 63849133c6dSPawel Jakub Dawidek (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold, 63949133c6dSPawel Jakub Dawidek sizeof(hold)); 64049133c6dSPawel Jakub Dawidek } 6418fae3551SRodney W. Grimes if (options & F_SO_DONTROUTE) 64249133c6dSPawel Jakub Dawidek (void)setsockopt(ssend, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 6438fae3551SRodney W. Grimes sizeof(hold)); 64481a6f4c7SRichard Scheffenegger if (options & F_IP_VLAN_PCP) { 64581a6f4c7SRichard Scheffenegger (void)setsockopt(ssend, IPPROTO_IP, IP_VLAN_PCP, (char *)&pcp, 64681a6f4c7SRichard Scheffenegger sizeof(pcp)); 64781a6f4c7SRichard Scheffenegger } 6489a4365d0SYoshinobu Inoue #ifdef IPSEC 6499a4365d0SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC 6509a4365d0SYoshinobu Inoue if (options & F_POLICY) { 6519a4365d0SYoshinobu Inoue char *buf; 6529a4365d0SYoshinobu Inoue if (policy_in != NULL) { 6539a4365d0SYoshinobu Inoue buf = ipsec_set_policy(policy_in, strlen(policy_in)); 6549a4365d0SYoshinobu Inoue if (buf == NULL) 655ffd40070SKris Kennaway errx(EX_CONFIG, "%s", ipsec_strerror()); 65649133c6dSPawel Jakub Dawidek if (setsockopt(srecv, IPPROTO_IP, IP_IPSEC_POLICY, 6579a4365d0SYoshinobu Inoue buf, ipsec_get_policylen(buf)) < 0) 6581ad0b1beSMaxim Konovalov err(EX_CONFIG, 6591ad0b1beSMaxim Konovalov "ipsec policy cannot be configured"); 6609a4365d0SYoshinobu Inoue free(buf); 6619a4365d0SYoshinobu Inoue } 6629a4365d0SYoshinobu Inoue 6639a4365d0SYoshinobu Inoue if (policy_out != NULL) { 6649a4365d0SYoshinobu Inoue buf = ipsec_set_policy(policy_out, strlen(policy_out)); 6659a4365d0SYoshinobu Inoue if (buf == NULL) 666ffd40070SKris Kennaway errx(EX_CONFIG, "%s", ipsec_strerror()); 66749133c6dSPawel Jakub Dawidek if (setsockopt(ssend, IPPROTO_IP, IP_IPSEC_POLICY, 6689a4365d0SYoshinobu Inoue buf, ipsec_get_policylen(buf)) < 0) 6691ad0b1beSMaxim Konovalov err(EX_CONFIG, 6701ad0b1beSMaxim Konovalov "ipsec policy cannot be configured"); 6719a4365d0SYoshinobu Inoue free(buf); 6729a4365d0SYoshinobu Inoue } 6739a4365d0SYoshinobu Inoue } 6749a4365d0SYoshinobu Inoue #endif /*IPSEC_POLICY_IPSEC*/ 6759a4365d0SYoshinobu Inoue #endif /*IPSEC*/ 6768fae3551SRodney W. Grimes 6770b2f8b3fSMaxim Konovalov if (options & F_HDRINCL) { 678d9cacf60SAlan Somers struct ip ip; 679d9cacf60SAlan Somers 680d9cacf60SAlan Somers memcpy(&ip, outpackhdr, sizeof(ip)); 6810b2f8b3fSMaxim Konovalov if (!(options & (F_TTL | F_MTTL))) { 6820b2f8b3fSMaxim Konovalov mib[0] = CTL_NET; 6830b2f8b3fSMaxim Konovalov mib[1] = PF_INET; 6840b2f8b3fSMaxim Konovalov mib[2] = IPPROTO_IP; 6850b2f8b3fSMaxim Konovalov mib[3] = IPCTL_DEFTTL; 6860b2f8b3fSMaxim Konovalov sz = sizeof(ttl); 6870b2f8b3fSMaxim Konovalov if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) 6880b2f8b3fSMaxim Konovalov err(1, "sysctl(net.inet.ip.ttl)"); 6890b2f8b3fSMaxim Konovalov } 69049133c6dSPawel Jakub Dawidek setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); 691d9cacf60SAlan Somers ip.ip_v = IPVERSION; 692d9cacf60SAlan Somers ip.ip_hl = sizeof(struct ip) >> 2; 693d9cacf60SAlan Somers ip.ip_tos = tos; 694d9cacf60SAlan Somers ip.ip_id = 0; 695d9cacf60SAlan Somers ip.ip_off = htons(df ? IP_DF : 0); 696d9cacf60SAlan Somers ip.ip_ttl = ttl; 697d9cacf60SAlan Somers ip.ip_p = IPPROTO_ICMP; 698d9cacf60SAlan Somers ip.ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; 699d9cacf60SAlan Somers ip.ip_dst = to->sin_addr; 700d9cacf60SAlan Somers memcpy(outpackhdr, &ip, sizeof(ip)); 7010b2f8b3fSMaxim Konovalov } 70249133c6dSPawel Jakub Dawidek 70349133c6dSPawel Jakub Dawidek /* 70449133c6dSPawel Jakub Dawidek * Here we enter capability mode. Further down access to global 70549133c6dSPawel Jakub Dawidek * namespaces (e.g filesystem) is restricted (see capsicum(4)). 70649133c6dSPawel Jakub Dawidek * We must connect(2) our socket before this point. 70749133c6dSPawel Jakub Dawidek */ 7087bdc3291SMark Johnston caph_cache_catpages(); 70918fcfaa4SMark Johnston if (caph_enter_casper() < 0) 710301bc9f9SAlan Somers err(1, "caph_enter_casper"); 71149133c6dSPawel Jakub Dawidek 71249133c6dSPawel Jakub Dawidek cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); 7137bdc3291SMark Johnston if (caph_rights_limit(srecv, &rights) < 0) 71449133c6dSPawel Jakub Dawidek err(1, "cap_rights_limit srecv"); 71549133c6dSPawel Jakub Dawidek cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); 7167bdc3291SMark Johnston if (caph_rights_limit(ssend, &rights) < 0) 71749133c6dSPawel Jakub Dawidek err(1, "cap_rights_limit ssend"); 71849133c6dSPawel Jakub Dawidek 7198fae3551SRodney W. Grimes /* record route option */ 7208fae3551SRodney W. Grimes if (options & F_RROUTE) { 7218fae3551SRodney W. Grimes #ifdef IP_OPTIONS 722039d6aa4SBill Fenner bzero(rspace, sizeof(rspace)); 7238fae3551SRodney W. Grimes rspace[IPOPT_OPTVAL] = IPOPT_RR; 7248fae3551SRodney W. Grimes rspace[IPOPT_OLEN] = sizeof(rspace) - 1; 7258fae3551SRodney W. Grimes rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 726039d6aa4SBill Fenner rspace[sizeof(rspace) - 1] = IPOPT_EOL; 72749133c6dSPawel Jakub Dawidek if (setsockopt(ssend, IPPROTO_IP, IP_OPTIONS, rspace, 72843470e3bSGarrett Wollman sizeof(rspace)) < 0) 72943470e3bSGarrett Wollman err(EX_OSERR, "setsockopt IP_OPTIONS"); 7308fae3551SRodney W. Grimes #else 73143470e3bSGarrett Wollman errx(EX_UNAVAILABLE, 73243470e3bSGarrett Wollman "record route not available in this implementation"); 7338fae3551SRodney W. Grimes #endif /* IP_OPTIONS */ 7348fae3551SRodney W. Grimes } 7358fae3551SRodney W. Grimes 736211bfbd2SRuslan Ermilov if (options & F_TTL) { 73749133c6dSPawel Jakub Dawidek if (setsockopt(ssend, IPPROTO_IP, IP_TTL, &ttl, 738211bfbd2SRuslan Ermilov sizeof(ttl)) < 0) { 739211bfbd2SRuslan Ermilov err(EX_OSERR, "setsockopt IP_TTL"); 740211bfbd2SRuslan Ermilov } 741211bfbd2SRuslan Ermilov } 74285456935SBill Fenner if (options & F_NOLOOP) { 74349133c6dSPawel Jakub Dawidek if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, 74485456935SBill Fenner sizeof(loop)) < 0) { 74543470e3bSGarrett Wollman err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); 74685456935SBill Fenner } 74785456935SBill Fenner } 74885456935SBill Fenner if (options & F_MTTL) { 74949133c6dSPawel Jakub Dawidek if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, 750211bfbd2SRuslan Ermilov sizeof(mttl)) < 0) { 75143470e3bSGarrett Wollman err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); 75285456935SBill Fenner } 75385456935SBill Fenner } 75485456935SBill Fenner if (options & F_MIF) { 75549133c6dSPawel Jakub Dawidek if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, 75685456935SBill Fenner sizeof(ifaddr)) < 0) { 75743470e3bSGarrett Wollman err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); 75885456935SBill Fenner } 75985456935SBill Fenner } 760039d6aa4SBill Fenner #ifdef SO_TIMESTAMP 76184633ef1SAlan Somers { 76284633ef1SAlan Somers int on = 1; 76384633ef1SAlan Somers int ts_clock = SO_TS_MONOTONIC; 76484633ef1SAlan Somers if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, 76584633ef1SAlan Somers sizeof(on)) < 0) 766039d6aa4SBill Fenner err(EX_OSERR, "setsockopt SO_TIMESTAMP"); 76784633ef1SAlan Somers if (setsockopt(srecv, SOL_SOCKET, SO_TS_CLOCK, &ts_clock, 76884633ef1SAlan Somers sizeof(ts_clock)) < 0) 76984633ef1SAlan Somers err(EX_OSERR, "setsockopt SO_TS_CLOCK"); 770039d6aa4SBill Fenner } 771039d6aa4SBill Fenner #endif 7729ff95228SGleb Smirnoff if (sweepmax) { 773bb7dfe5eSGleb Smirnoff if (sweepmin > sweepmax) 77478e1f68eSMark Johnston errx(EX_USAGE, 77578e1f68eSMark Johnston "Maximum packet size must be no less than the minimum packet size"); 77678e1f68eSMark Johnston 77778e1f68eSMark Johnston if (sweepmax > maxpayload - TIMEVAL_LEN) 77878e1f68eSMark Johnston errx(EX_USAGE, "Invalid sweep maximum"); 7799ff95228SGleb Smirnoff 7809ff95228SGleb Smirnoff if (datalen != DEFDATALEN) 78178e1f68eSMark Johnston errx(EX_USAGE, 78278e1f68eSMark Johnston "Packet size and ping sweep are mutually exclusive"); 7839ff95228SGleb Smirnoff 7849ff95228SGleb Smirnoff if (npackets > 0) { 7859ff95228SGleb Smirnoff snpackets = npackets; 7869ff95228SGleb Smirnoff npackets = 0; 7879ff95228SGleb Smirnoff } else 7889ff95228SGleb Smirnoff snpackets = 1; 7899ff95228SGleb Smirnoff datalen = sweepmin; 7909ff95228SGleb Smirnoff send_len = icmp_len + sweepmin; 7919ff95228SGleb Smirnoff } 7929ff95228SGleb Smirnoff if (options & F_SWEEP && !sweepmax) 7939ff95228SGleb Smirnoff errx(EX_USAGE, "Maximum sweep size must be specified"); 79485456935SBill Fenner 7958fae3551SRodney W. Grimes /* 7968fae3551SRodney W. Grimes * When pinging the broadcast address, you can get a lot of answers. 7978fae3551SRodney W. Grimes * Doing something so evil is useful if you are trying to stress the 7988fae3551SRodney W. Grimes * ethernet, or just want to fill the arp cache to get some stuff for 79943470e3bSGarrett Wollman * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast 80043470e3bSGarrett Wollman * or multicast pings if they wish. 8018fae3551SRodney W. Grimes */ 8024fba6582SMaxim Konovalov 8034fba6582SMaxim Konovalov /* 8044fba6582SMaxim Konovalov * XXX receive buffer needs undetermined space for mbuf overhead 8054fba6582SMaxim Konovalov * as well. 8064fba6582SMaxim Konovalov */ 8074fba6582SMaxim Konovalov hold = IP_MAXPACKET + 128; 80849133c6dSPawel Jakub Dawidek (void)setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 8098fae3551SRodney W. Grimes sizeof(hold)); 81049133c6dSPawel Jakub Dawidek /* CAP_SETSOCKOPT removed */ 81149133c6dSPawel Jakub Dawidek cap_rights_init(&rights, CAP_RECV, CAP_EVENT); 8127bdc3291SMark Johnston if (caph_rights_limit(srecv, &rights) < 0) 81349133c6dSPawel Jakub Dawidek err(1, "cap_rights_limit srecv setsockopt"); 814261e59bbSMaxim Konovalov if (uid == 0) 81549133c6dSPawel Jakub Dawidek (void)setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, (char *)&hold, 816e8bd25ceSRobert Watson sizeof(hold)); 81749133c6dSPawel Jakub Dawidek /* CAP_SETSOCKOPT removed */ 81849133c6dSPawel Jakub Dawidek cap_rights_init(&rights, CAP_SEND); 8197bdc3291SMark Johnston if (caph_rights_limit(ssend, &rights) < 0) 82049133c6dSPawel Jakub Dawidek err(1, "cap_rights_limit ssend setsockopt"); 821e8bd25ceSRobert Watson 82299490edeSWarner Losh if (to->sin_family == AF_INET) { 82399490edeSWarner Losh (void)printf("PING %s (%s)", hostname, 82499490edeSWarner Losh inet_ntoa(to->sin_addr)); 82599490edeSWarner Losh if (source) 82699490edeSWarner Losh (void)printf(" from %s", shostname); 8279ff95228SGleb Smirnoff if (sweepmax) 8289ff95228SGleb Smirnoff (void)printf(": (%d ... %d) data bytes\n", 8299ff95228SGleb Smirnoff sweepmin, sweepmax); 8309ff95228SGleb Smirnoff else 83199490edeSWarner Losh (void)printf(": %d data bytes\n", datalen); 8329ff95228SGleb Smirnoff 8339ff95228SGleb Smirnoff } else { 8349ff95228SGleb Smirnoff if (sweepmax) 8359ff95228SGleb Smirnoff (void)printf("PING %s: (%d ... %d) data bytes\n", 8369ff95228SGleb Smirnoff hostname, sweepmin, sweepmax); 8379ff95228SGleb Smirnoff else 8388fae3551SRodney W. Grimes (void)printf("PING %s: %d data bytes\n", hostname, datalen); 8399ff95228SGleb Smirnoff } 8408fae3551SRodney W. Grimes 8417d81b35cSBruce Evans /* 842a2a00888SSean Eric Fagan * Use sigaction() instead of signal() to get unambiguous semantics, 843a2a00888SSean Eric Fagan * in particular with SA_RESTART not set. 8447d81b35cSBruce Evans */ 845a2a00888SSean Eric Fagan 846f6bd468bSPaul Traina sigemptyset(&si_sa.sa_mask); 84737e5b2c6SSean Eric Fagan si_sa.sa_flags = 0; 84803d4d1c7SJose Luis Duran si_sa.sa_handler = onsignal; 84903d4d1c7SJose Luis Duran if (sigaction(SIGINT, &si_sa, 0) == -1) 850a2a00888SSean Eric Fagan err(EX_OSERR, "sigaction SIGINT"); 85103d4d1c7SJose Luis Duran seenint = 0; 85203d4d1c7SJose Luis Duran if (sigaction(SIGINFO, &si_sa, 0) == -1) 85372d3e667SJose Luis Duran err(EX_OSERR, "sigaction SIGINFO"); 85403d4d1c7SJose Luis Duran seeninfo = 0; 855bf113f1bSBill Fumerola if (alarmtimeout > 0) { 8567237fd94SBill Fumerola if (sigaction(SIGALRM, &si_sa, 0) == -1) 8577237fd94SBill Fumerola err(EX_OSERR, "sigaction SIGALRM"); 858bf113f1bSBill Fumerola } 85937e5b2c6SSean Eric Fagan 860039d6aa4SBill Fenner bzero(&msg, sizeof(msg)); 861039d6aa4SBill Fenner msg.msg_name = (caddr_t)&from; 862039d6aa4SBill Fenner msg.msg_iov = &iov; 863039d6aa4SBill Fenner msg.msg_iovlen = 1; 864039d6aa4SBill Fenner #ifdef SO_TIMESTAMP 865039d6aa4SBill Fenner msg.msg_control = (caddr_t)ctrl; 86667511a4cSAlan Somers msg.msg_controllen = sizeof(ctrl); 867039d6aa4SBill Fenner #endif 868039d6aa4SBill Fenner iov.iov_base = packet; 869e88178ddSMaxim Konovalov iov.iov_len = IP_MAXPACKET; 870039d6aa4SBill Fenner 87132af342fSRuslan Ermilov if (preload == 0) 87232af342fSRuslan Ermilov pinger(); /* send the first ping */ 87332af342fSRuslan Ermilov else { 87432af342fSRuslan Ermilov if (npackets != 0 && preload > npackets) 87532af342fSRuslan Ermilov preload = npackets; 8768fae3551SRodney W. Grimes while (preload--) /* fire off them quickies */ 8778fae3551SRodney W. Grimes pinger(); 87832af342fSRuslan Ermilov } 8791ad76f1bSAlan Somers (void)clock_gettime(CLOCK_MONOTONIC, &last); 8808fae3551SRodney W. Grimes 881039d6aa4SBill Fenner if (options & F_FLOOD) { 882039d6aa4SBill Fenner intvl.tv_sec = 0; 8831ad76f1bSAlan Somers intvl.tv_nsec = 10000000; 884039d6aa4SBill Fenner } else { 885526f06b2SMatthew Dillon intvl.tv_sec = interval / 1000; 8861ad76f1bSAlan Somers intvl.tv_nsec = interval % 1000 * 1000000; 887039d6aa4SBill Fenner } 888039d6aa4SBill Fenner 889261e59bbSMaxim Konovalov almost_done = 0; 89003d4d1c7SJose Luis Duran while (seenint == 0) { 8911ad76f1bSAlan Somers struct timespec now, timeout; 892039d6aa4SBill Fenner fd_set rfds; 893d9cacf60SAlan Somers int n; 894d9cacf60SAlan Somers ssize_t cc; 8958fae3551SRodney W. Grimes 89603d4d1c7SJose Luis Duran /* signal handling */ 89703d4d1c7SJose Luis Duran if (seeninfo) { 89803d4d1c7SJose Luis Duran pr_summary(stderr); 89903d4d1c7SJose Luis Duran seeninfo = 0; 90003d4d1c7SJose Luis Duran continue; 90103d4d1c7SJose Luis Duran } 90249133c6dSPawel Jakub Dawidek if ((unsigned)srecv >= FD_SETSIZE) 9037e5bbd68SJacques Vidrine errx(EX_OSERR, "descriptor too large"); 904039d6aa4SBill Fenner FD_ZERO(&rfds); 90549133c6dSPawel Jakub Dawidek FD_SET(srecv, &rfds); 9061ad76f1bSAlan Somers (void)clock_gettime(CLOCK_MONOTONIC, &now); 9071ad76f1bSAlan Somers timespecadd(&last, &intvl, &timeout); 9081ad76f1bSAlan Somers timespecsub(&timeout, &now, &timeout); 909039d6aa4SBill Fenner if (timeout.tv_sec < 0) 9101ad76f1bSAlan Somers timespecclear(&timeout); 91103d4d1c7SJose Luis Duran 9121ad76f1bSAlan Somers n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL); 9135e2cc0f4SStephen McKay if (n < 0) 91403d4d1c7SJose Luis Duran continue; /* EINTR */ 915039d6aa4SBill Fenner if (n == 1) { 9161ad76f1bSAlan Somers struct timespec *tv = NULL; 917039d6aa4SBill Fenner #ifdef SO_TIMESTAMP 91867511a4cSAlan Somers struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 919039d6aa4SBill Fenner #endif 920039d6aa4SBill Fenner msg.msg_namelen = sizeof(from); 92149133c6dSPawel Jakub Dawidek if ((cc = recvmsg(srecv, &msg, 0)) < 0) { 9228fae3551SRodney W. Grimes if (errno == EINTR) 9238fae3551SRodney W. Grimes continue; 924e345a80dSPhilippe Charnier warn("recvmsg"); 9258fae3551SRodney W. Grimes continue; 9268fae3551SRodney W. Grimes } 92746d7b45aSTom Jones /* If we have a 0 byte read from recvfrom continue */ 92846d7b45aSTom Jones if (cc == 0) 92946d7b45aSTom Jones continue; 930039d6aa4SBill Fenner #ifdef SO_TIMESTAMP 931b17fb992SAlan Somers if (cmsg != NULL && 932b17fb992SAlan Somers cmsg->cmsg_level == SOL_SOCKET && 933039d6aa4SBill Fenner cmsg->cmsg_type == SCM_TIMESTAMP && 93431eac03bSSean Chittenden cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) { 935fa05a94cSJohn Birrell /* Copy to avoid alignment problems: */ 936fa05a94cSJohn Birrell memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); 93731eac03bSSean Chittenden tv = &now; 938fa05a94cSJohn Birrell } 939039d6aa4SBill Fenner #endif 94031eac03bSSean Chittenden if (tv == NULL) { 9411ad76f1bSAlan Somers (void)clock_gettime(CLOCK_MONOTONIC, &now); 94231eac03bSSean Chittenden tv = &now; 943039d6aa4SBill Fenner } 94431eac03bSSean Chittenden pr_pack((char *)packet, cc, &from, tv); 94531eac03bSSean Chittenden if ((options & F_ONCE && nreceived) || 94631eac03bSSean Chittenden (npackets && nreceived >= npackets)) 9478fae3551SRodney W. Grimes break; 9488fae3551SRodney W. Grimes } 94903d4d1c7SJose Luis Duran if (n == 0 || (options & F_FLOOD)) { 9509ff95228SGleb Smirnoff if (sweepmax && sntransmitted == snpackets) { 95178e1f68eSMark Johnston if (datalen + sweepincr > sweepmax) 95278e1f68eSMark Johnston break; 95378e1f68eSMark Johnston for (i = 0; i < sweepincr; i++) 9549ff95228SGleb Smirnoff *datap++ = i; 9559ff95228SGleb Smirnoff datalen += sweepincr; 9569ff95228SGleb Smirnoff send_len = icmp_len + datalen; 9579ff95228SGleb Smirnoff sntransmitted = 0; 9589ff95228SGleb Smirnoff } 959039d6aa4SBill Fenner if (!npackets || ntransmitted < npackets) 960039d6aa4SBill Fenner pinger(); 961039d6aa4SBill Fenner else { 962039d6aa4SBill Fenner if (almost_done) 963039d6aa4SBill Fenner break; 964039d6aa4SBill Fenner almost_done = 1; 96503d4d1c7SJose Luis Duran /* 96603d4d1c7SJose Luis Duran * If we're not transmitting any more packets, 96703d4d1c7SJose Luis Duran * change the timer to wait two round-trip times 96803d4d1c7SJose Luis Duran * if we've received any packets or (waittime) 96903d4d1c7SJose Luis Duran * milliseconds if we haven't. 97003d4d1c7SJose Luis Duran */ 9711ad76f1bSAlan Somers intvl.tv_nsec = 0; 972039d6aa4SBill Fenner if (nreceived) { 973039d6aa4SBill Fenner intvl.tv_sec = 2 * tmax / 1000; 97403d4d1c7SJose Luis Duran if (intvl.tv_sec == 0) 975039d6aa4SBill Fenner intvl.tv_sec = 1; 976d6cd1497SGleb Smirnoff } else { 977d6cd1497SGleb Smirnoff intvl.tv_sec = waittime / 1000; 97803d4d1c7SJose Luis Duran intvl.tv_nsec = 97903d4d1c7SJose Luis Duran waittime % 1000 * 1000000; 980d6cd1497SGleb Smirnoff } 981039d6aa4SBill Fenner } 9821ad76f1bSAlan Somers (void)clock_gettime(CLOCK_MONOTONIC, &last); 98325107197SIan Dowse if (ntransmitted - nreceived - 1 > nmissedmax) { 98425107197SIan Dowse nmissedmax = ntransmitted - nreceived - 1; 98525107197SIan Dowse if (options & F_MISSED) 986ca517ad8SPoul-Henning Kamp (void)write(STDOUT_FILENO, &BBELL, 1); 987039d6aa4SBill Fenner } 988039d6aa4SBill Fenner } 98925107197SIan Dowse } 99003d4d1c7SJose Luis Duran pr_summary(stdout); 9918fae3551SRodney W. Grimes 99203d4d1c7SJose Luis Duran exit(nreceived ? 0 : 2); 993515dd2faSJulian Elischer } 994515dd2faSJulian Elischer 995515dd2faSJulian Elischer /* 9968fae3551SRodney W. Grimes * pinger -- 9978fae3551SRodney W. Grimes * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 9988fae3551SRodney W. Grimes * will be added on by the kernel. The ID field is our UNIX process ID, 999eb1543c6SMatthew N. Dodd * and the sequence number is an ascending integer. The first TIMEVAL_LEN 10001ad76f1bSAlan Somers * bytes of the data portion are used to hold a UNIX "timespec" struct in 10014fba6582SMaxim Konovalov * host byte-order, to compute the round-trip time. 10028fae3551SRodney W. Grimes */ 100343470e3bSGarrett Wollman static void 100443470e3bSGarrett Wollman pinger(void) 10058fae3551SRodney W. Grimes { 10061ad76f1bSAlan Somers struct timespec now; 100713e3f0b7SMaxim Konovalov struct tv32 tv32; 1008d9cacf60SAlan Somers struct icmp icp; 1009efc8588dSDavid E. O'Brien int cc, i; 10100b2f8b3fSMaxim Konovalov u_char *packet; 10118fae3551SRodney W. Grimes 10120b2f8b3fSMaxim Konovalov packet = outpack; 1013d9cacf60SAlan Somers memcpy(&icp, outpack, ICMP_MINLEN + phdr_len); 1014d9cacf60SAlan Somers icp.icmp_type = icmp_type; 1015d9cacf60SAlan Somers icp.icmp_code = 0; 1016d9cacf60SAlan Somers icp.icmp_cksum = 0; 1017d9cacf60SAlan Somers icp.icmp_seq = htons(ntransmitted); 1018d9cacf60SAlan Somers icp.icmp_id = ident; /* ID */ 10198fae3551SRodney W. Grimes 10205db89bc7SBill Fenner CLR(ntransmitted % mx_dup_ck); 10218fae3551SRodney W. Grimes 1022eb1543c6SMatthew N. Dodd if ((options & F_TIME) || timing) { 10231ad76f1bSAlan Somers (void)clock_gettime(CLOCK_MONOTONIC, &now); 10241ad76f1bSAlan Somers /* 10251ad76f1bSAlan Somers * Truncate seconds down to 32 bits in order 10261ad76f1bSAlan Somers * to fit the timestamp within 8 bytes of the 10271ad76f1bSAlan Somers * packet. We're only concerned with 10281ad76f1bSAlan Somers * durations, not absolute times. 10291ad76f1bSAlan Somers */ 10301ad76f1bSAlan Somers tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); 10311ad76f1bSAlan Somers tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec); 1032eb1543c6SMatthew N. Dodd if (options & F_TIME) 1033d9cacf60SAlan Somers icp.icmp_otime = htonl((now.tv_sec % (24*60*60)) 10341ad76f1bSAlan Somers * 1000 + now.tv_nsec / 1000000); 1035eb1543c6SMatthew N. Dodd if (timing) 103613e3f0b7SMaxim Konovalov bcopy((void *)&tv32, 10370fe0c0ccSMaxim Konovalov (void *)&outpack[ICMP_MINLEN + phdr_len], 103813e3f0b7SMaxim Konovalov sizeof(tv32)); 1039eb1543c6SMatthew N. Dodd } 1040eb1543c6SMatthew N. Dodd 1041d9cacf60SAlan Somers memcpy(outpack, &icp, ICMP_MINLEN + phdr_len); 1042d9cacf60SAlan Somers 10430fe0c0ccSMaxim Konovalov cc = ICMP_MINLEN + phdr_len + datalen; 10448fae3551SRodney W. Grimes 10458fae3551SRodney W. Grimes /* compute ICMP checksum here */ 1046d9cacf60SAlan Somers icp.icmp_cksum = in_cksum(outpack, cc); 1047d9cacf60SAlan Somers /* Update icmp_cksum in the raw packet data buffer. */ 1048d9cacf60SAlan Somers memcpy(outpack + offsetof(struct icmp, icmp_cksum), &icp.icmp_cksum, 1049d9cacf60SAlan Somers sizeof(icp.icmp_cksum)); 10508fae3551SRodney W. Grimes 10510b2f8b3fSMaxim Konovalov if (options & F_HDRINCL) { 1052d9cacf60SAlan Somers struct ip ip; 1053d9cacf60SAlan Somers 10540b2f8b3fSMaxim Konovalov cc += sizeof(struct ip); 1055d9cacf60SAlan Somers ip.ip_len = htons(cc); 1056d9cacf60SAlan Somers /* Update ip_len in the raw packet data buffer. */ 1057d9cacf60SAlan Somers memcpy(outpackhdr + offsetof(struct ip, ip_len), &ip.ip_len, 1058d9cacf60SAlan Somers sizeof(ip.ip_len)); 1059d9cacf60SAlan Somers ip.ip_sum = in_cksum(outpackhdr, cc); 1060d9cacf60SAlan Somers /* Update ip_sum in the raw packet data buffer. */ 1061d9cacf60SAlan Somers memcpy(outpackhdr + offsetof(struct ip, ip_sum), &ip.ip_sum, 1062d9cacf60SAlan Somers sizeof(ip.ip_sum)); 10630b2f8b3fSMaxim Konovalov packet = outpackhdr; 10640b2f8b3fSMaxim Konovalov } 106549133c6dSPawel Jakub Dawidek i = send(ssend, (char *)packet, cc, 0); 10668fae3551SRodney W. Grimes if (i < 0 || i != cc) { 106743470e3bSGarrett Wollman if (i < 0) { 10688f975bb3SBruce Evans if (options & F_FLOOD && errno == ENOBUFS) { 1069515dd2faSJulian Elischer usleep(FLOOD_BACKOFF); 1070515dd2faSJulian Elischer return; 1071515dd2faSJulian Elischer } 107243470e3bSGarrett Wollman warn("sendto"); 107343470e3bSGarrett Wollman } else { 107443470e3bSGarrett Wollman warn("%s: partial write: %d of %d bytes", 1075416aa49bSPoul-Henning Kamp hostname, i, cc); 10768fae3551SRodney W. Grimes } 1077363d7bbeSJulian Elischer } 1078363d7bbeSJulian Elischer ntransmitted++; 10799ff95228SGleb Smirnoff sntransmitted++; 1080d399eb3eSPiotr Pawel Stefaniak if (!(options & F_QUIET) && options & F_DOT) 1081d399eb3eSPiotr Pawel Stefaniak (void)write(STDOUT_FILENO, &DOT[DOTidx++ % DOTlen], 1); 10828fae3551SRodney W. Grimes } 10838fae3551SRodney W. Grimes 10848fae3551SRodney W. Grimes /* 10858fae3551SRodney W. Grimes * pr_pack -- 10868fae3551SRodney W. Grimes * Print out the packet, if it came from us. This logic is necessary 10878fae3551SRodney W. Grimes * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 10888fae3551SRodney W. Grimes * which arrive ('tis only fair). This permits multiple copies of this 10898fae3551SRodney W. Grimes * program to be run without having intermingled output (or statistics!). 10908fae3551SRodney W. Grimes */ 109143470e3bSGarrett Wollman static void 1092d9cacf60SAlan Somers pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) 10938fae3551SRodney W. Grimes { 10949b219646SPeter Wemm struct in_addr ina; 1095d9cacf60SAlan Somers u_char *cp, *dp, l; 1096d9cacf60SAlan Somers struct icmp icp; 1097d9cacf60SAlan Somers struct ip ip; 1098d9cacf60SAlan Somers const u_char *icmp_data_raw; 109946d7b45aSTom Jones ssize_t icmp_data_raw_len; 11008f975bb3SBruce Evans double triptime; 110146d7b45aSTom Jones int dupflag, i, j, recv_len; 110270960bb8SCy Schubert int8_t hlen; 11032c29d74cSAlan Somers uint16_t seq; 1104efc8588dSDavid E. O'Brien static int old_rrlen; 1105efc8588dSDavid E. O'Brien static char old_rr[MAX_IPOPTLEN]; 1106d9cacf60SAlan Somers struct ip oip; 1107d9cacf60SAlan Somers u_char oip_header_len; 1108d9cacf60SAlan Somers struct icmp oicmp; 11094630a325SJose Luis Duran const u_char *oicmp_raw; 1110d9cacf60SAlan Somers 1111d9cacf60SAlan Somers /* 111246d7b45aSTom Jones * Get size of IP header of the received packet. 111346d7b45aSTom Jones * The header length is contained in the lower four bits of the first 111446d7b45aSTom Jones * byte and represents the number of 4 byte octets the header takes up. 111546d7b45aSTom Jones * 111646d7b45aSTom Jones * The IHL minimum value is 5 (20 bytes) and its maximum value is 15 111746d7b45aSTom Jones * (60 bytes). 1118d9cacf60SAlan Somers */ 1119d9cacf60SAlan Somers memcpy(&l, buf, sizeof(l)); 1120d9cacf60SAlan Somers hlen = (l & 0x0f) << 2; 11218fae3551SRodney W. Grimes 112246d7b45aSTom Jones /* Reject IP packets with a short header */ 112370960bb8SCy Schubert if (hlen < (int8_t) sizeof(struct ip)) { 112446d7b45aSTom Jones if (options & F_VERBOSE) 112546d7b45aSTom Jones warn("IHL too short (%d bytes) from %s", hlen, 112646d7b45aSTom Jones inet_ntoa(from->sin_addr)); 112746d7b45aSTom Jones return; 112846d7b45aSTom Jones } 112946d7b45aSTom Jones 113046d7b45aSTom Jones memcpy(&ip, buf, sizeof(struct ip)); 113146d7b45aSTom Jones 113246d7b45aSTom Jones /* Check packet has enough data to carry a valid ICMP header */ 1133e88178ddSMaxim Konovalov recv_len = cc; 11348fae3551SRodney W. Grimes if (cc < hlen + ICMP_MINLEN) { 11358fae3551SRodney W. Grimes if (options & F_VERBOSE) 1136d9cacf60SAlan Somers warn("packet too short (%zd bytes) from %s", cc, 113743470e3bSGarrett Wollman inet_ntoa(from->sin_addr)); 11388fae3551SRodney W. Grimes return; 11398fae3551SRodney W. Grimes } 11408fae3551SRodney W. Grimes 114146d7b45aSTom Jones icmp_data_raw_len = cc - (hlen + offsetof(struct icmp, icmp_data)); 1142d9cacf60SAlan Somers icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_data); 1143d9cacf60SAlan Somers 11448fae3551SRodney W. Grimes /* Now the ICMP part */ 11458fae3551SRodney W. Grimes cc -= hlen; 1146d9cacf60SAlan Somers memcpy(&icp, buf + hlen, MIN((ssize_t)sizeof(icp), cc)); 1147d9cacf60SAlan Somers if (icp.icmp_type == icmp_type_rsp) { 1148d9cacf60SAlan Somers if (icp.icmp_id != ident) 11498fae3551SRodney W. Grimes return; /* 'Twas not our ECHO */ 11508fae3551SRodney W. Grimes ++nreceived; 11518f975bb3SBruce Evans triptime = 0.0; 11528fae3551SRodney W. Grimes if (timing) { 11531ad76f1bSAlan Somers struct timespec tv1; 115413e3f0b7SMaxim Konovalov struct tv32 tv32; 1155d9cacf60SAlan Somers const u_char *tp; 1156d9cacf60SAlan Somers 1157d9cacf60SAlan Somers tp = icmp_data_raw + phdr_len; 1158143008a1SMatthew N. Dodd 11597e9489e0SHiroki Sato if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= 11607e9489e0SHiroki Sato sizeof(tv1)) { 11619d2b0ab8SPeter Wemm /* Copy to avoid alignment problems: */ 116213e3f0b7SMaxim Konovalov memcpy(&tv32, tp, sizeof(tv32)); 116313e3f0b7SMaxim Konovalov tv1.tv_sec = ntohl(tv32.tv32_sec); 11641ad76f1bSAlan Somers tv1.tv_nsec = ntohl(tv32.tv32_nsec); 11651ad76f1bSAlan Somers timespecsub(tv, &tv1, tv); 1166039d6aa4SBill Fenner triptime = ((double)tv->tv_sec) * 1000.0 + 11671ad76f1bSAlan Somers ((double)tv->tv_nsec) / 1000000.0; 1168ea6d1692SJose Luis Duran if (triptime < 0) { 1169ea6d1692SJose Luis Duran warnx("time of day goes back (%.3f ms)," 1170ea6d1692SJose Luis Duran " clamping time to 0", 1171ea6d1692SJose Luis Duran triptime); 1172ea6d1692SJose Luis Duran triptime = 0; 1173ea6d1692SJose Luis Duran } 11748fae3551SRodney W. Grimes tsum += triptime; 11753109a910SGarrett Wollman tsumsq += triptime * triptime; 11768fae3551SRodney W. Grimes if (triptime < tmin) 11778fae3551SRodney W. Grimes tmin = triptime; 11788fae3551SRodney W. Grimes if (triptime > tmax) 11798fae3551SRodney W. Grimes tmax = triptime; 118047e9b3eaSMatthew N. Dodd } else 118147e9b3eaSMatthew N. Dodd timing = 0; 11828fae3551SRodney W. Grimes } 11838fae3551SRodney W. Grimes 1184d9cacf60SAlan Somers seq = ntohs(icp.icmp_seq); 11855db89bc7SBill Fenner 11865db89bc7SBill Fenner if (TST(seq % mx_dup_ck)) { 11878fae3551SRodney W. Grimes ++nrepeats; 11888fae3551SRodney W. Grimes --nreceived; 11898fae3551SRodney W. Grimes dupflag = 1; 11908fae3551SRodney W. Grimes } else { 11915db89bc7SBill Fenner SET(seq % mx_dup_ck); 11928fae3551SRodney W. Grimes dupflag = 0; 11938fae3551SRodney W. Grimes } 11948fae3551SRodney W. Grimes 11958fae3551SRodney W. Grimes if (options & F_QUIET) 11968fae3551SRodney W. Grimes return; 11978fae3551SRodney W. Grimes 1198d6cd1497SGleb Smirnoff if (options & F_WAITTIME && triptime > waittime) { 1199d6cd1497SGleb Smirnoff ++nrcvtimeout; 1200d6cd1497SGleb Smirnoff return; 1201d6cd1497SGleb Smirnoff } 1202d6cd1497SGleb Smirnoff 1203d399eb3eSPiotr Pawel Stefaniak if (options & F_DOT) 12048fae3551SRodney W. Grimes (void)write(STDOUT_FILENO, &BSPACE, 1); 12058fae3551SRodney W. Grimes else { 1206d9cacf60SAlan Somers (void)printf("%zd bytes from %s: icmp_seq=%u", cc, 1207229e8bf2SAlan Somers pr_addr(from->sin_addr), seq); 1208d9cacf60SAlan Somers (void)printf(" ttl=%d", ip.ip_ttl); 12098fae3551SRodney W. Grimes if (timing) 1210d410b6f1SDavid Greenman (void)printf(" time=%.3f ms", triptime); 12118fae3551SRodney W. Grimes if (dupflag) 12128fae3551SRodney W. Grimes (void)printf(" (DUP!)"); 1213772dfa72SDaniel O'Callaghan if (options & F_AUDIBLE) 1214ca517ad8SPoul-Henning Kamp (void)write(STDOUT_FILENO, &BBELL, 1); 1215143008a1SMatthew N. Dodd if (options & F_MASK) { 1216143008a1SMatthew N. Dodd /* Just prentend this cast isn't ugly */ 1217143008a1SMatthew N. Dodd (void)printf(" mask=%s", 1218d9cacf60SAlan Somers inet_ntoa(*(struct in_addr *)&(icp.icmp_mask))); 1219143008a1SMatthew N. Dodd } 1220eb1543c6SMatthew N. Dodd if (options & F_TIME) { 1221d9cacf60SAlan Somers (void)printf(" tso=%s", pr_ntime(icp.icmp_otime)); 1222d9cacf60SAlan Somers (void)printf(" tsr=%s", pr_ntime(icp.icmp_rtime)); 1223d9cacf60SAlan Somers (void)printf(" tst=%s", pr_ntime(icp.icmp_ttime)); 1224eb1543c6SMatthew N. Dodd } 1225e88178ddSMaxim Konovalov if (recv_len != send_len) { 1226e88178ddSMaxim Konovalov (void)printf( 1227e88178ddSMaxim Konovalov "\nwrong total length %d instead of %d", 1228e88178ddSMaxim Konovalov recv_len, send_len); 1229e88178ddSMaxim Konovalov } 12308fae3551SRodney W. Grimes /* check the data */ 1231d9cacf60SAlan Somers cp = (u_char*)(buf + hlen + offsetof(struct icmp, 1232d9cacf60SAlan Somers icmp_data) + phdr_len); 12330fe0c0ccSMaxim Konovalov dp = &outpack[ICMP_MINLEN + phdr_len]; 123447e9b3eaSMatthew N. Dodd cc -= ICMP_MINLEN + phdr_len; 123529dccd6aSMaxim Konovalov i = 0; 123629dccd6aSMaxim Konovalov if (timing) { /* don't check variable timestamp */ 123729dccd6aSMaxim Konovalov cp += TIMEVAL_LEN; 123829dccd6aSMaxim Konovalov dp += TIMEVAL_LEN; 123929dccd6aSMaxim Konovalov cc -= TIMEVAL_LEN; 124029dccd6aSMaxim Konovalov i += TIMEVAL_LEN; 124129dccd6aSMaxim Konovalov } 124229dccd6aSMaxim Konovalov for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) { 12438fae3551SRodney W. Grimes if (*cp != *dp) { 12448fae3551SRodney W. Grimes (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 12458fae3551SRodney W. Grimes i, *dp, *cp); 12461ad0b1beSMaxim Konovalov (void)printf("\ncp:"); 1247d9cacf60SAlan Somers cp = (u_char*)(buf + hlen + 1248d9cacf60SAlan Somers offsetof(struct icmp, icmp_data)); 1249d32ff037SJohn Birrell for (i = 0; i < datalen; ++i, ++cp) { 1250e88178ddSMaxim Konovalov if ((i % 16) == 8) 1251d32ff037SJohn Birrell (void)printf("\n\t"); 1252e88178ddSMaxim Konovalov (void)printf(" %2x", *cp); 1253d32ff037SJohn Birrell } 12541ad0b1beSMaxim Konovalov (void)printf("\ndp:"); 12550fe0c0ccSMaxim Konovalov cp = &outpack[ICMP_MINLEN]; 1256d32ff037SJohn Birrell for (i = 0; i < datalen; ++i, ++cp) { 1257e88178ddSMaxim Konovalov if ((i % 16) == 8) 12588fae3551SRodney W. Grimes (void)printf("\n\t"); 1259e88178ddSMaxim Konovalov (void)printf(" %2x", *cp); 12608fae3551SRodney W. Grimes } 12618fae3551SRodney W. Grimes break; 12628fae3551SRodney W. Grimes } 12638fae3551SRodney W. Grimes } 12648fae3551SRodney W. Grimes } 12658fae3551SRodney W. Grimes } else { 1266ef9e6dc7SBill Fenner /* 1267ef9e6dc7SBill Fenner * We've got something other than an ECHOREPLY. 1268ef9e6dc7SBill Fenner * See if it's a reply to something that we sent. 1269ef9e6dc7SBill Fenner * We can compare IP destination, protocol, 1270ef9e6dc7SBill Fenner * and ICMP type and ID. 1271f78ac61bSWarner Losh * 1272f78ac61bSWarner Losh * Only print all the error messages if we are running 1273f78ac61bSWarner Losh * as root to avoid leaking information not normally 1274f78ac61bSWarner Losh * available to those not running as root. 1275ef9e6dc7SBill Fenner */ 127646d7b45aSTom Jones 127746d7b45aSTom Jones /* 127846d7b45aSTom Jones * If we don't have enough bytes for a quoted IP header and an 127946d7b45aSTom Jones * ICMP header then stop. 128046d7b45aSTom Jones */ 128146d7b45aSTom Jones if (icmp_data_raw_len < 128246d7b45aSTom Jones (ssize_t)(sizeof(struct ip) + sizeof(struct icmp))) { 128346d7b45aSTom Jones if (options & F_VERBOSE) 128446d7b45aSTom Jones warnx("quoted data too short (%zd bytes) from %s", 128546d7b45aSTom Jones icmp_data_raw_len, inet_ntoa(from->sin_addr)); 128646d7b45aSTom Jones return; 128746d7b45aSTom Jones } 128846d7b45aSTom Jones 1289d9cacf60SAlan Somers memcpy(&oip_header_len, icmp_data_raw, sizeof(oip_header_len)); 1290d9cacf60SAlan Somers oip_header_len = (oip_header_len & 0x0f) << 2; 129146d7b45aSTom Jones 129246d7b45aSTom Jones /* Reject IP packets with a short header */ 129346d7b45aSTom Jones if (oip_header_len < sizeof(struct ip)) { 129446d7b45aSTom Jones if (options & F_VERBOSE) 129546d7b45aSTom Jones warnx("inner IHL too short (%d bytes) from %s", 129646d7b45aSTom Jones oip_header_len, inet_ntoa(from->sin_addr)); 129746d7b45aSTom Jones return; 129846d7b45aSTom Jones } 129946d7b45aSTom Jones 130046d7b45aSTom Jones /* 130146d7b45aSTom Jones * Check against the actual IHL length, to protect against 130246d7b45aSTom Jones * quoated packets carrying IP options. 130346d7b45aSTom Jones */ 130446d7b45aSTom Jones if (icmp_data_raw_len < 130546d7b45aSTom Jones (ssize_t)(oip_header_len + sizeof(struct icmp))) { 130646d7b45aSTom Jones if (options & F_VERBOSE) 130746d7b45aSTom Jones warnx("inner packet too short (%zd bytes) from %s", 130846d7b45aSTom Jones icmp_data_raw_len, inet_ntoa(from->sin_addr)); 130946d7b45aSTom Jones return; 131046d7b45aSTom Jones } 131146d7b45aSTom Jones 131246d7b45aSTom Jones memcpy(&oip, icmp_data_raw, sizeof(struct ip)); 13134630a325SJose Luis Duran oicmp_raw = icmp_data_raw + oip_header_len; 13144630a325SJose Luis Duran memcpy(&oicmp, oicmp_raw, sizeof(struct icmp)); 1315ef9e6dc7SBill Fenner 1316ee2bf734SWarner Losh if (((options & F_VERBOSE) && uid == 0) || 1317ef9e6dc7SBill Fenner (!(options & F_QUIET2) && 1318d9cacf60SAlan Somers (oip.ip_dst.s_addr == whereto.sin_addr.s_addr) && 1319d9cacf60SAlan Somers (oip.ip_p == IPPROTO_ICMP) && 1320d9cacf60SAlan Somers (oicmp.icmp_type == ICMP_ECHO) && 1321d9cacf60SAlan Somers (oicmp.icmp_id == ident))) { 1322d9cacf60SAlan Somers (void)printf("%zd bytes from %s: ", cc, 132343470e3bSGarrett Wollman pr_addr(from->sin_addr)); 132420b41303SJose Luis Duran pr_icmph(&icp, &oip, icmp_data_raw); 1325ef9e6dc7SBill Fenner } else 1326ef9e6dc7SBill Fenner return; 13278fae3551SRodney W. Grimes } 13288fae3551SRodney W. Grimes 13298fae3551SRodney W. Grimes /* Display any IP options */ 13308fae3551SRodney W. Grimes cp = (u_char *)buf + sizeof(struct ip); 13318fae3551SRodney W. Grimes 13328fae3551SRodney W. Grimes for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 13338fae3551SRodney W. Grimes switch (*cp) { 13348fae3551SRodney W. Grimes case IPOPT_EOL: 13358fae3551SRodney W. Grimes hlen = 0; 13368fae3551SRodney W. Grimes break; 13378fae3551SRodney W. Grimes case IPOPT_LSRR: 1338cb75aca7SMaxim Konovalov case IPOPT_SSRR: 1339cb75aca7SMaxim Konovalov (void)printf(*cp == IPOPT_LSRR ? 1340cb75aca7SMaxim Konovalov "\nLSRR: " : "\nSSRR: "); 1341301207dfSMaxim Konovalov j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1; 13428fae3551SRodney W. Grimes hlen -= 2; 1343301207dfSMaxim Konovalov cp += 2; 13443c721ab3SMaxim Konovalov if (j >= INADDR_LEN && 13453c721ab3SMaxim Konovalov j <= hlen - (int)sizeof(struct ip)) { 13468fae3551SRodney W. Grimes for (;;) { 1347301207dfSMaxim Konovalov bcopy(++cp, &ina.s_addr, INADDR_LEN); 1348301207dfSMaxim Konovalov if (ina.s_addr == 0) 13491ad0b1beSMaxim Konovalov (void)printf("\t0.0.0.0"); 1350301207dfSMaxim Konovalov else 13511ad0b1beSMaxim Konovalov (void)printf("\t%s", 13521ad0b1beSMaxim Konovalov pr_addr(ina)); 1353301207dfSMaxim Konovalov hlen -= INADDR_LEN; 1354301207dfSMaxim Konovalov cp += INADDR_LEN - 1; 1355301207dfSMaxim Konovalov j -= INADDR_LEN; 1356301207dfSMaxim Konovalov if (j < INADDR_LEN) 13578fae3551SRodney W. Grimes break; 13588fae3551SRodney W. Grimes (void)putchar('\n'); 13598fae3551SRodney W. Grimes } 1360301207dfSMaxim Konovalov } else 1361d2c9a140SJose Luis Duran (void)printf("\t(truncated route)"); 13628fae3551SRodney W. Grimes break; 13638fae3551SRodney W. Grimes case IPOPT_RR: 1364301207dfSMaxim Konovalov j = cp[IPOPT_OLEN]; /* get length */ 1365301207dfSMaxim Konovalov i = cp[IPOPT_OFFSET]; /* and pointer */ 13668fae3551SRodney W. Grimes hlen -= 2; 1367301207dfSMaxim Konovalov cp += 2; 13688fae3551SRodney W. Grimes if (i > j) 13698fae3551SRodney W. Grimes i = j; 1370301207dfSMaxim Konovalov i = i - IPOPT_MINOFF + 1; 1371301207dfSMaxim Konovalov if (i < 0 || i > (hlen - (int)sizeof(struct ip))) { 1372301207dfSMaxim Konovalov old_rrlen = 0; 13738fae3551SRodney W. Grimes continue; 1374301207dfSMaxim Konovalov } 13758fae3551SRodney W. Grimes if (i == old_rrlen 13768fae3551SRodney W. Grimes && !bcmp((char *)cp, old_rr, i) 1377d399eb3eSPiotr Pawel Stefaniak && !(options & F_DOT)) { 13788fae3551SRodney W. Grimes (void)printf("\t(same route)"); 13798fae3551SRodney W. Grimes hlen -= i; 13808fae3551SRodney W. Grimes cp += i; 13818fae3551SRodney W. Grimes break; 13828fae3551SRodney W. Grimes } 13838fae3551SRodney W. Grimes old_rrlen = i; 13848fae3551SRodney W. Grimes bcopy((char *)cp, old_rr, i); 13858fae3551SRodney W. Grimes (void)printf("\nRR: "); 1386301207dfSMaxim Konovalov if (i >= INADDR_LEN && 1387301207dfSMaxim Konovalov i <= hlen - (int)sizeof(struct ip)) { 13888fae3551SRodney W. Grimes for (;;) { 1389301207dfSMaxim Konovalov bcopy(++cp, &ina.s_addr, INADDR_LEN); 1390301207dfSMaxim Konovalov if (ina.s_addr == 0) 13911ad0b1beSMaxim Konovalov (void)printf("\t0.0.0.0"); 1392301207dfSMaxim Konovalov else 1393301207dfSMaxim Konovalov (void)printf("\t%s", 1394301207dfSMaxim Konovalov pr_addr(ina)); 1395301207dfSMaxim Konovalov hlen -= INADDR_LEN; 1396301207dfSMaxim Konovalov cp += INADDR_LEN - 1; 1397301207dfSMaxim Konovalov i -= INADDR_LEN; 1398301207dfSMaxim Konovalov if (i < INADDR_LEN) 13998fae3551SRodney W. Grimes break; 14008fae3551SRodney W. Grimes (void)putchar('\n'); 14018fae3551SRodney W. Grimes } 1402301207dfSMaxim Konovalov } else 1403301207dfSMaxim Konovalov (void)printf("\t(truncated route)"); 14048fae3551SRodney W. Grimes break; 14058fae3551SRodney W. Grimes case IPOPT_NOP: 14068fae3551SRodney W. Grimes (void)printf("\nNOP"); 14078fae3551SRodney W. Grimes break; 14088fae3551SRodney W. Grimes default: 14098fae3551SRodney W. Grimes (void)printf("\nunknown option %x", *cp); 14108fae3551SRodney W. Grimes break; 14118fae3551SRodney W. Grimes } 1412d399eb3eSPiotr Pawel Stefaniak if (!(options & F_DOT)) { 14138fae3551SRodney W. Grimes (void)putchar('\n'); 14148fae3551SRodney W. Grimes (void)fflush(stdout); 14158fae3551SRodney W. Grimes } 14168fae3551SRodney W. Grimes } 14178fae3551SRodney W. Grimes 14188fae3551SRodney W. Grimes /* 14198fae3551SRodney W. Grimes * pr_icmph -- 14208fae3551SRodney W. Grimes * Print a descriptive string about an ICMP header. 14218fae3551SRodney W. Grimes */ 142243470e3bSGarrett Wollman static void 1423d9cacf60SAlan Somers pr_icmph(struct icmp *icp, struct ip *oip, const u_char *const oicmp_raw) 14248fae3551SRodney W. Grimes { 1425efc8588dSDavid E. O'Brien 14268fae3551SRodney W. Grimes switch(icp->icmp_type) { 14278fae3551SRodney W. Grimes case ICMP_ECHOREPLY: 14288fae3551SRodney W. Grimes (void)printf("Echo Reply\n"); 14298fae3551SRodney W. Grimes /* XXX ID + Seq + Data */ 14308fae3551SRodney W. Grimes break; 14318fae3551SRodney W. Grimes case ICMP_UNREACH: 14328fae3551SRodney W. Grimes switch(icp->icmp_code) { 14338fae3551SRodney W. Grimes case ICMP_UNREACH_NET: 14348fae3551SRodney W. Grimes (void)printf("Destination Net Unreachable\n"); 14358fae3551SRodney W. Grimes break; 14368fae3551SRodney W. Grimes case ICMP_UNREACH_HOST: 14378fae3551SRodney W. Grimes (void)printf("Destination Host Unreachable\n"); 14388fae3551SRodney W. Grimes break; 14398fae3551SRodney W. Grimes case ICMP_UNREACH_PROTOCOL: 14408fae3551SRodney W. Grimes (void)printf("Destination Protocol Unreachable\n"); 14418fae3551SRodney W. Grimes break; 14428fae3551SRodney W. Grimes case ICMP_UNREACH_PORT: 14438fae3551SRodney W. Grimes (void)printf("Destination Port Unreachable\n"); 14448fae3551SRodney W. Grimes break; 14458fae3551SRodney W. Grimes case ICMP_UNREACH_NEEDFRAG: 1446ef9e6dc7SBill Fenner (void)printf("frag needed and DF set (MTU %d)\n", 1447ff49597eSBill Fenner ntohs(icp->icmp_nextmtu)); 14488fae3551SRodney W. Grimes break; 14498fae3551SRodney W. Grimes case ICMP_UNREACH_SRCFAIL: 14508fae3551SRodney W. Grimes (void)printf("Source Route Failed\n"); 14518fae3551SRodney W. Grimes break; 1452ef9e6dc7SBill Fenner case ICMP_UNREACH_FILTER_PROHIB: 1453ef9e6dc7SBill Fenner (void)printf("Communication prohibited by filter\n"); 1454ef9e6dc7SBill Fenner break; 14558fae3551SRodney W. Grimes default: 14568fae3551SRodney W. Grimes (void)printf("Dest Unreachable, Bad Code: %d\n", 14578fae3551SRodney W. Grimes icp->icmp_code); 14588fae3551SRodney W. Grimes break; 14598fae3551SRodney W. Grimes } 14608fae3551SRodney W. Grimes /* Print returned IP header information */ 14611dc1f6bdSJose Luis Duran pr_iph(oip, oicmp_raw); 14628fae3551SRodney W. Grimes break; 14638fae3551SRodney W. Grimes case ICMP_SOURCEQUENCH: 14648fae3551SRodney W. Grimes (void)printf("Source Quench\n"); 14651dc1f6bdSJose Luis Duran pr_iph(oip, oicmp_raw); 14668fae3551SRodney W. Grimes break; 14678fae3551SRodney W. Grimes case ICMP_REDIRECT: 14688fae3551SRodney W. Grimes switch(icp->icmp_code) { 14698fae3551SRodney W. Grimes case ICMP_REDIRECT_NET: 14708fae3551SRodney W. Grimes (void)printf("Redirect Network"); 14718fae3551SRodney W. Grimes break; 14728fae3551SRodney W. Grimes case ICMP_REDIRECT_HOST: 14738fae3551SRodney W. Grimes (void)printf("Redirect Host"); 14748fae3551SRodney W. Grimes break; 14758fae3551SRodney W. Grimes case ICMP_REDIRECT_TOSNET: 14768fae3551SRodney W. Grimes (void)printf("Redirect Type of Service and Network"); 14778fae3551SRodney W. Grimes break; 14788fae3551SRodney W. Grimes case ICMP_REDIRECT_TOSHOST: 14798fae3551SRodney W. Grimes (void)printf("Redirect Type of Service and Host"); 14808fae3551SRodney W. Grimes break; 14818fae3551SRodney W. Grimes default: 14828fae3551SRodney W. Grimes (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 14838fae3551SRodney W. Grimes break; 14848fae3551SRodney W. Grimes } 1485ff49597eSBill Fenner (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); 14861dc1f6bdSJose Luis Duran pr_iph(oip, oicmp_raw); 14878fae3551SRodney W. Grimes break; 14888fae3551SRodney W. Grimes case ICMP_ECHO: 14898fae3551SRodney W. Grimes (void)printf("Echo Request\n"); 14908fae3551SRodney W. Grimes /* XXX ID + Seq + Data */ 14918fae3551SRodney W. Grimes break; 14928fae3551SRodney W. Grimes case ICMP_TIMXCEED: 14938fae3551SRodney W. Grimes switch(icp->icmp_code) { 14948fae3551SRodney W. Grimes case ICMP_TIMXCEED_INTRANS: 14958fae3551SRodney W. Grimes (void)printf("Time to live exceeded\n"); 14968fae3551SRodney W. Grimes break; 14978fae3551SRodney W. Grimes case ICMP_TIMXCEED_REASS: 14988fae3551SRodney W. Grimes (void)printf("Frag reassembly time exceeded\n"); 14998fae3551SRodney W. Grimes break; 15008fae3551SRodney W. Grimes default: 15018fae3551SRodney W. Grimes (void)printf("Time exceeded, Bad Code: %d\n", 15028fae3551SRodney W. Grimes icp->icmp_code); 15038fae3551SRodney W. Grimes break; 15048fae3551SRodney W. Grimes } 15051dc1f6bdSJose Luis Duran pr_iph(oip, oicmp_raw); 15068fae3551SRodney W. Grimes break; 15078fae3551SRodney W. Grimes case ICMP_PARAMPROB: 15088fae3551SRodney W. Grimes (void)printf("Parameter problem: pointer = 0x%02x\n", 15098fae3551SRodney W. Grimes icp->icmp_hun.ih_pptr); 15101dc1f6bdSJose Luis Duran pr_iph(oip, oicmp_raw); 15118fae3551SRodney W. Grimes break; 15128fae3551SRodney W. Grimes case ICMP_TSTAMP: 15138fae3551SRodney W. Grimes (void)printf("Timestamp\n"); 15148fae3551SRodney W. Grimes /* XXX ID + Seq + 3 timestamps */ 15158fae3551SRodney W. Grimes break; 15168fae3551SRodney W. Grimes case ICMP_TSTAMPREPLY: 15178fae3551SRodney W. Grimes (void)printf("Timestamp Reply\n"); 15188fae3551SRodney W. Grimes /* XXX ID + Seq + 3 timestamps */ 15198fae3551SRodney W. Grimes break; 15208fae3551SRodney W. Grimes case ICMP_IREQ: 15218fae3551SRodney W. Grimes (void)printf("Information Request\n"); 15228fae3551SRodney W. Grimes /* XXX ID + Seq */ 15238fae3551SRodney W. Grimes break; 15248fae3551SRodney W. Grimes case ICMP_IREQREPLY: 15258fae3551SRodney W. Grimes (void)printf("Information Reply\n"); 15268fae3551SRodney W. Grimes /* XXX ID + Seq */ 15278fae3551SRodney W. Grimes break; 15288fae3551SRodney W. Grimes case ICMP_MASKREQ: 15298fae3551SRodney W. Grimes (void)printf("Address Mask Request\n"); 15308fae3551SRodney W. Grimes break; 15318fae3551SRodney W. Grimes case ICMP_MASKREPLY: 15328fae3551SRodney W. Grimes (void)printf("Address Mask Reply\n"); 15338fae3551SRodney W. Grimes break; 1534ef9e6dc7SBill Fenner case ICMP_ROUTERADVERT: 1535ef9e6dc7SBill Fenner (void)printf("Router Advertisement\n"); 1536ef9e6dc7SBill Fenner break; 1537ef9e6dc7SBill Fenner case ICMP_ROUTERSOLICIT: 1538ef9e6dc7SBill Fenner (void)printf("Router Solicitation\n"); 1539ef9e6dc7SBill Fenner break; 15408fae3551SRodney W. Grimes default: 15418fae3551SRodney W. Grimes (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 15428fae3551SRodney W. Grimes } 15438fae3551SRodney W. Grimes } 15448fae3551SRodney W. Grimes 15458fae3551SRodney W. Grimes /* 15468fae3551SRodney W. Grimes * pr_iph -- 15478fae3551SRodney W. Grimes * Print an IP header with options. 15488fae3551SRodney W. Grimes */ 154943470e3bSGarrett Wollman static void 155020b41303SJose Luis Duran pr_iph(struct ip *ip, const u_char *cp) 15518fae3551SRodney W. Grimes { 1552b86e4812SJose Luis Duran struct in_addr dst_ina, src_ina; 1553efc8588dSDavid E. O'Brien int hlen; 15548fae3551SRodney W. Grimes 15558fae3551SRodney W. Grimes hlen = ip->ip_hl << 2; 155620b41303SJose Luis Duran cp = cp + sizeof(struct ip); /* point to options */ 15578fae3551SRodney W. Grimes 1558b86e4812SJose Luis Duran memcpy(&src_ina, &ip->ip_src.s_addr, sizeof(src_ina)); 1559b86e4812SJose Luis Duran memcpy(&dst_ina, &ip->ip_dst.s_addr, sizeof(dst_ina)); 1560b86e4812SJose Luis Duran 1561b86e4812SJose Luis Duran (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks %*s %*s", 1562b86e4812SJose Luis Duran (int)strlen(inet_ntoa(src_ina)), "Src", 1563b86e4812SJose Luis Duran (int)strlen(inet_ntoa(dst_ina)), "Dst"); 1564b86e4812SJose Luis Duran if (hlen > (int)sizeof(struct ip)) 1565b86e4812SJose Luis Duran (void)printf(" Opts"); 1566b86e4812SJose Luis Duran (void)putchar('\n'); 15678fae3551SRodney W. Grimes (void)printf(" %1x %1x %02x %04x %04x", 1568ef9e6dc7SBill Fenner ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 1569ef9e6dc7SBill Fenner ntohs(ip->ip_id)); 15709185854dSJose Luis Duran (void)printf(" %1x %04x", 15719185854dSJose Luis Duran (ntohs(ip->ip_off) & 0xe000) >> 13, 15729185854dSJose Luis Duran ntohs(ip->ip_off) & 0x1fff); 1573ef9e6dc7SBill Fenner (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 1574ef9e6dc7SBill Fenner ntohs(ip->ip_sum)); 1575b86e4812SJose Luis Duran (void)printf(" %s", inet_ntoa(src_ina)); 1576b86e4812SJose Luis Duran (void)printf(" %s", inet_ntoa(dst_ina)); 1577ef9e6dc7SBill Fenner /* dump any option bytes */ 1578b86e4812SJose Luis Duran if (hlen > (int)sizeof(struct ip)) { 1579b86e4812SJose Luis Duran (void)printf(" "); 1580491263d7SJose Luis Duran while (hlen-- > (int)sizeof(struct ip)) { 15818fae3551SRodney W. Grimes (void)printf("%02x", *cp++); 15828fae3551SRodney W. Grimes } 1583b86e4812SJose Luis Duran } 15848fae3551SRodney W. Grimes (void)putchar('\n'); 15858fae3551SRodney W. Grimes } 15868fae3551SRodney W. Grimes 15878fae3551SRodney W. Grimes /* 15888fae3551SRodney W. Grimes * pr_addr -- 15898fae3551SRodney W. Grimes * Return an ascii host address as a dotted quad and optionally with 15908fae3551SRodney W. Grimes * a hostname. 15918fae3551SRodney W. Grimes */ 159243470e3bSGarrett Wollman static char * 1593fafb8f11SEd Schouten pr_addr(struct in_addr ina) 15948fae3551SRodney W. Grimes { 15958fae3551SRodney W. Grimes struct hostent *hp; 1596f78ac61bSWarner Losh static char buf[16 + 3 + MAXHOSTNAMELEN]; 15978fae3551SRodney W. Grimes 159803d4d1c7SJose Luis Duran if (!(options & F_HOSTNAME)) 159943470e3bSGarrett Wollman return inet_ntoa(ina); 160049133c6dSPawel Jakub Dawidek 1601491263d7SJose Luis Duran hp = cap_gethostbyaddr(capdns, (char *)&ina, sizeof(ina), AF_INET); 160249133c6dSPawel Jakub Dawidek 160349133c6dSPawel Jakub Dawidek if (hp == NULL) 160449133c6dSPawel Jakub Dawidek return inet_ntoa(ina); 160549133c6dSPawel Jakub Dawidek 1606efa38539SPeter Wemm (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 160743470e3bSGarrett Wollman inet_ntoa(ina)); 16088fae3551SRodney W. Grimes return(buf); 16098fae3551SRodney W. Grimes } 16108fae3551SRodney W. Grimes 1611eb1543c6SMatthew N. Dodd static char * 1612007fe4e3SMaxim Konovalov pr_ntime(n_time timestamp) 1613eb1543c6SMatthew N. Dodd { 16147898770aSAlan Somers static char buf[11]; 1615007fe4e3SMaxim Konovalov int hour, min, sec; 1616eb1543c6SMatthew N. Dodd 1617007fe4e3SMaxim Konovalov sec = ntohl(timestamp) / 1000; 1618007fe4e3SMaxim Konovalov hour = sec / 60 / 60; 1619007fe4e3SMaxim Konovalov min = (sec % (60 * 60)) / 60; 1620007fe4e3SMaxim Konovalov sec = (sec % (60 * 60)) % 60; 1621eb1543c6SMatthew N. Dodd 1622007fe4e3SMaxim Konovalov (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec); 1623eb1543c6SMatthew N. Dodd 1624eb1543c6SMatthew N. Dodd return (buf); 1625eb1543c6SMatthew N. Dodd } 1626eb1543c6SMatthew N. Dodd 162743470e3bSGarrett Wollman static void 1628fafb8f11SEd Schouten fill(char *bp, char *patp) 16298fae3551SRodney W. Grimes { 16308fae3551SRodney W. Grimes char *cp; 1631efc8588dSDavid E. O'Brien int pat[16]; 16324fba6582SMaxim Konovalov u_int ii, jj, kk; 16338fae3551SRodney W. Grimes 163443470e3bSGarrett Wollman for (cp = patp; *cp; cp++) { 163543470e3bSGarrett Wollman if (!isxdigit(*cp)) 163643470e3bSGarrett Wollman errx(EX_USAGE, 163743470e3bSGarrett Wollman "patterns must be specified as hex digits"); 163843470e3bSGarrett Wollman 16398fae3551SRodney W. Grimes } 16408fae3551SRodney W. Grimes ii = sscanf(patp, 16418fae3551SRodney W. Grimes "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 16428fae3551SRodney W. Grimes &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 16438fae3551SRodney W. Grimes &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 16448fae3551SRodney W. Grimes &pat[13], &pat[14], &pat[15]); 16458fae3551SRodney W. Grimes 16468fae3551SRodney W. Grimes if (ii > 0) 1647d829c3dfSMatthew N. Dodd for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii) 16488fae3551SRodney W. Grimes for (jj = 0; jj < ii; ++jj) 16498fae3551SRodney W. Grimes bp[jj + kk] = pat[jj]; 16508fae3551SRodney W. Grimes if (!(options & F_QUIET)) { 16518fae3551SRodney W. Grimes (void)printf("PATTERN: 0x"); 16528fae3551SRodney W. Grimes for (jj = 0; jj < ii; ++jj) 16538fae3551SRodney W. Grimes (void)printf("%02x", bp[jj] & 0xFF); 16548fae3551SRodney W. Grimes (void)printf("\n"); 16558fae3551SRodney W. Grimes } 16568fae3551SRodney W. Grimes } 16578fae3551SRodney W. Grimes 165849133c6dSPawel Jakub Dawidek static cap_channel_t * 165949133c6dSPawel Jakub Dawidek capdns_setup(void) 166049133c6dSPawel Jakub Dawidek { 166149133c6dSPawel Jakub Dawidek cap_channel_t *capcas, *capdnsloc; 1662a3ce7698SAlan Somers #ifdef WITH_CASPER 166349133c6dSPawel Jakub Dawidek const char *types[2]; 166449133c6dSPawel Jakub Dawidek int families[1]; 1665a3ce7698SAlan Somers #endif 166649133c6dSPawel Jakub Dawidek capcas = cap_init(); 1667c501d73cSMariusz Zaborski if (capcas == NULL) 1668c501d73cSMariusz Zaborski err(1, "unable to create casper process"); 166949133c6dSPawel Jakub Dawidek capdnsloc = cap_service_open(capcas, "system.dns"); 167049133c6dSPawel Jakub Dawidek /* Casper capability no longer needed. */ 167149133c6dSPawel Jakub Dawidek cap_close(capcas); 167249133c6dSPawel Jakub Dawidek if (capdnsloc == NULL) 167349133c6dSPawel Jakub Dawidek err(1, "unable to open system.dns service"); 1674a3ce7698SAlan Somers #ifdef WITH_CASPER 1675752d135eSMariusz Zaborski types[0] = "NAME2ADDR"; 1676752d135eSMariusz Zaborski types[1] = "ADDR2NAME"; 167749133c6dSPawel Jakub Dawidek if (cap_dns_type_limit(capdnsloc, types, 2) < 0) 167849133c6dSPawel Jakub Dawidek err(1, "unable to limit access to system.dns service"); 167949133c6dSPawel Jakub Dawidek families[0] = AF_INET; 168049133c6dSPawel Jakub Dawidek if (cap_dns_family_limit(capdnsloc, families, 1) < 0) 168149133c6dSPawel Jakub Dawidek err(1, "unable to limit access to system.dns service"); 1682a3ce7698SAlan Somers #endif 168349133c6dSPawel Jakub Dawidek return (capdnsloc); 168449133c6dSPawel Jakub Dawidek } 1685