1  | 
     | 
     | 
    /*	$OpenBSD: ping.c,v 1.224 2017/11/08 17:27:39 visa Exp $	*/  | 
    
    
    2  | 
     | 
     | 
     | 
    
    
    3  | 
     | 
     | 
    /*  | 
    
    
    4  | 
     | 
     | 
     * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.  | 
    
    
    5  | 
     | 
     | 
     * All rights reserved.  | 
    
    
    6  | 
     | 
     | 
     *  | 
    
    
    7  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    8  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    9  | 
     | 
     | 
     * are met:  | 
    
    
    10  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    11  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    12  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    13  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    14  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    15  | 
     | 
     | 
     * 3. Neither the name of the project nor the names of its contributors  | 
    
    
    16  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    17  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    18  | 
     | 
     | 
     *  | 
    
    
    19  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    20  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    21  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    22  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE  | 
    
    
    23  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    24  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    25  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    26  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    27  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    28  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    29  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    30  | 
     | 
     | 
     */  | 
    
    
    31  | 
     | 
     | 
     | 
    
    
    32  | 
     | 
     | 
    /*  | 
    
    
    33  | 
     | 
     | 
     * Copyright (c) 1989, 1993  | 
    
    
    34  | 
     | 
     | 
     *	The Regents of the University of California.  All rights reserved.  | 
    
    
    35  | 
     | 
     | 
     *  | 
    
    
    36  | 
     | 
     | 
     * This code is derived from software contributed to Berkeley by  | 
    
    
    37  | 
     | 
     | 
     * Mike Muuss.  | 
    
    
    38  | 
     | 
     | 
     *  | 
    
    
    39  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    40  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    41  | 
     | 
     | 
     * are met:  | 
    
    
    42  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    43  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    44  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    45  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    46  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    47  | 
     | 
     | 
     * 3. Neither the name of the University nor the names of its contributors  | 
    
    
    48  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    49  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    50  | 
     | 
     | 
     *  | 
    
    
    51  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    52  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    53  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    54  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  | 
    
    
    55  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    56  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    57  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    58  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    59  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    60  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    61  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    62  | 
     | 
     | 
     */  | 
    
    
    63  | 
     | 
     | 
     | 
    
    
    64  | 
     | 
     | 
    /*  | 
    
    
    65  | 
     | 
     | 
     * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,  | 
    
    
    66  | 
     | 
     | 
     * measure round-trip-delays and packet loss across network paths.  | 
    
    
    67  | 
     | 
     | 
     *  | 
    
    
    68  | 
     | 
     | 
     * Author -  | 
    
    
    69  | 
     | 
     | 
     *	Mike Muuss  | 
    
    
    70  | 
     | 
     | 
     *	U. S. Army Ballistic Research Laboratory  | 
    
    
    71  | 
     | 
     | 
     *	December, 1983  | 
    
    
    72  | 
     | 
     | 
     *  | 
    
    
    73  | 
     | 
     | 
     * Status -  | 
    
    
    74  | 
     | 
     | 
     *	Public Domain.  Distribution Unlimited.  | 
    
    
    75  | 
     | 
     | 
     * Bugs -  | 
    
    
    76  | 
     | 
     | 
     *	More statistics could always be gathered.  | 
    
    
    77  | 
     | 
     | 
     *	This program has to run SUID to ROOT to access the ICMP socket.  | 
    
    
    78  | 
     | 
     | 
     */  | 
    
    
    79  | 
     | 
     | 
     | 
    
    
    80  | 
     | 
     | 
    #include <sys/types.h>  | 
    
    
    81  | 
     | 
     | 
    #include <sys/socket.h>  | 
    
    
    82  | 
     | 
     | 
    #include <sys/time.h>  | 
    
    
    83  | 
     | 
     | 
    #include <sys/uio.h>  | 
    
    
    84  | 
     | 
     | 
     | 
    
    
    85  | 
     | 
     | 
    #include <netinet/in.h>  | 
    
    
    86  | 
     | 
     | 
    #include <netinet/ip.h>  | 
    
    
    87  | 
     | 
     | 
    #include <netinet/ip_icmp.h>  | 
    
    
    88  | 
     | 
     | 
    #include <netinet/ip_var.h>  | 
    
    
    89  | 
     | 
     | 
    #include <netinet/ip6.h>  | 
    
    
    90  | 
     | 
     | 
    #include <netinet/icmp6.h>  | 
    
    
    91  | 
     | 
     | 
    #include <netinet/ip_ah.h>  | 
    
    
    92  | 
     | 
     | 
    #include <arpa/inet.h>  | 
    
    
    93  | 
     | 
     | 
    #include <netdb.h>  | 
    
    
    94  | 
     | 
     | 
     | 
    
    
    95  | 
     | 
     | 
    #include <ctype.h>  | 
    
    
    96  | 
     | 
     | 
    #include <err.h>  | 
    
    
    97  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    98  | 
     | 
     | 
    #include <limits.h>  | 
    
    
    99  | 
     | 
     | 
    #include <math.h>  | 
    
    
    100  | 
     | 
     | 
    #include <poll.h>  | 
    
    
    101  | 
     | 
     | 
    #include <pwd.h>  | 
    
    
    102  | 
     | 
     | 
    #include <signal.h>  | 
    
    
    103  | 
     | 
     | 
    #include <siphash.h>  | 
    
    
    104  | 
     | 
     | 
    #include <stdint.h>  | 
    
    
    105  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    106  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    107  | 
     | 
     | 
    #include <string.h>  | 
    
    
    108  | 
     | 
     | 
    #include <time.h>  | 
    
    
    109  | 
     | 
     | 
    #include <unistd.h>  | 
    
    
    110  | 
     | 
     | 
     | 
    
    
    111  | 
     | 
     | 
    struct tv64 { | 
    
    
    112  | 
     | 
     | 
    	u_int64_t	tv64_sec;  | 
    
    
    113  | 
     | 
     | 
    	u_int64_t	tv64_nsec;  | 
    
    
    114  | 
     | 
     | 
    };  | 
    
    
    115  | 
     | 
     | 
     | 
    
    
    116  | 
     | 
     | 
    struct payload { | 
    
    
    117  | 
     | 
     | 
    	struct tv64	tv64;  | 
    
    
    118  | 
     | 
     | 
    	u_int8_t	mac[SIPHASH_DIGEST_LENGTH];  | 
    
    
    119  | 
     | 
     | 
    };  | 
    
    
    120  | 
     | 
     | 
     | 
    
    
    121  | 
     | 
     | 
    #define	ECHOLEN		8	/* icmp echo header len excluding time */  | 
    
    
    122  | 
     | 
     | 
    #define	ECHOTMLEN	sizeof(struct payload)  | 
    
    
    123  | 
     | 
     | 
    #define	DEFDATALEN	(64 - ECHOLEN)		/* default data length */  | 
    
    
    124  | 
     | 
     | 
    #define	MAXIPLEN	60  | 
    
    
    125  | 
     | 
     | 
    #define	MAXICMPLEN	76  | 
    
    
    126  | 
     | 
     | 
    #define	MAXPAYLOAD	(IP_MAXPACKET - MAXIPLEN - ECHOLEN)  | 
    
    
    127  | 
     | 
     | 
    #define	IP6LEN		40  | 
    
    
    128  | 
     | 
     | 
    #define	EXTRA		256	/* for AH and various other headers. weird. */  | 
    
    
    129  | 
     | 
     | 
    #define	MAXPAYLOAD6	IPV6_MAXPACKET - IP6LEN - ECHOLEN  | 
    
    
    130  | 
     | 
     | 
    #define	MAXWAIT_DEFAULT	10			/* secs to wait for response */  | 
    
    
    131  | 
     | 
     | 
    #define	NROUTES		9			/* number of record route slots */  | 
    
    
    132  | 
     | 
     | 
     | 
    
    
    133  | 
     | 
     | 
    #define	A(bit)		rcvd_tbl[(bit)>>3]	/* identify byte in array */  | 
    
    
    134  | 
     | 
     | 
    #define	B(bit)		(1 << ((bit) & 0x07))	/* identify bit in byte */  | 
    
    
    135  | 
     | 
     | 
    #define	SET(bit)	(A(bit) |= B(bit))  | 
    
    
    136  | 
     | 
     | 
    #define	CLR(bit)	(A(bit) &= (~B(bit)))  | 
    
    
    137  | 
     | 
     | 
    #define	TST(bit)	(A(bit) & B(bit))  | 
    
    
    138  | 
     | 
     | 
     | 
    
    
    139  | 
     | 
     | 
    /* various options */  | 
    
    
    140  | 
     | 
     | 
    int options;  | 
    
    
    141  | 
     | 
     | 
    #define	F_FLOOD		0x0001  | 
    
    
    142  | 
     | 
     | 
    #define	F_INTERVAL	0x0002  | 
    
    
    143  | 
     | 
     | 
    #define	F_HOSTNAME	0x0004  | 
    
    
    144  | 
     | 
     | 
    #define	F_PINGFILLED	0x0008  | 
    
    
    145  | 
     | 
     | 
    #define	F_QUIET		0x0010  | 
    
    
    146  | 
     | 
     | 
    #define	F_RROUTE	0x0020  | 
    
    
    147  | 
     | 
     | 
    #define	F_SO_DEBUG	0x0040  | 
    
    
    148  | 
     | 
     | 
    /*			0x0080 */  | 
    
    
    149  | 
     | 
     | 
    #define	F_VERBOSE	0x0100  | 
    
    
    150  | 
     | 
     | 
    /*			0x0200 */  | 
    
    
    151  | 
     | 
     | 
    #define	F_HDRINCL	0x0400  | 
    
    
    152  | 
     | 
     | 
    #define	F_TTL		0x0800  | 
    
    
    153  | 
     | 
     | 
    /*			0x1000 */  | 
    
    
    154  | 
     | 
     | 
    #define	F_AUD_RECV	0x2000  | 
    
    
    155  | 
     | 
     | 
    #define	F_AUD_MISS	0x4000  | 
    
    
    156  | 
     | 
     | 
     | 
    
    
    157  | 
     | 
     | 
    /* multicast options */  | 
    
    
    158  | 
     | 
     | 
    int moptions;  | 
    
    
    159  | 
     | 
     | 
    #define	MULTICAST_NOLOOP	0x001  | 
    
    
    160  | 
     | 
     | 
    #define	MULTICAST_TTL		0x002  | 
    
    
    161  | 
     | 
     | 
     | 
    
    
    162  | 
     | 
     | 
    #define	DUMMY_PORT	10101  | 
    
    
    163  | 
     | 
     | 
    #define	PING_USER	"_ping"  | 
    
    
    164  | 
     | 
     | 
     | 
    
    
    165  | 
     | 
     | 
    /*  | 
    
    
    166  | 
     | 
     | 
     * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum  | 
    
    
    167  | 
     | 
     | 
     * number of received sequence numbers we can keep track of.  Change 128  | 
    
    
    168  | 
     | 
     | 
     * to 8192 for complete accuracy...  | 
    
    
    169  | 
     | 
     | 
     */  | 
    
    
    170  | 
     | 
     | 
    #define	MAX_DUP_CHK	(8 * 8192)  | 
    
    
    171  | 
     | 
     | 
    int mx_dup_ck = MAX_DUP_CHK;  | 
    
    
    172  | 
     | 
     | 
    char rcvd_tbl[MAX_DUP_CHK / 8];  | 
    
    
    173  | 
     | 
     | 
     | 
    
    
    174  | 
     | 
     | 
    int datalen = DEFDATALEN;  | 
    
    
    175  | 
     | 
     | 
    int maxpayload = MAXPAYLOAD;  | 
    
    
    176  | 
     | 
     | 
    u_char outpackhdr[IP_MAXPACKET+sizeof(struct ip)];  | 
    
    
    177  | 
     | 
     | 
    u_char *outpack = outpackhdr+sizeof(struct ip);  | 
    
    
    178  | 
     | 
     | 
    char BSPACE = '\b';		/* characters written for flood */  | 
    
    
    179  | 
     | 
     | 
    char DOT = '.';  | 
    
    
    180  | 
     | 
     | 
    char *hostname;  | 
    
    
    181  | 
     | 
     | 
    int ident;			/* process id to identify our packets */  | 
    
    
    182  | 
     | 
     | 
    int v6flag = 0;			/* are we ping6? */  | 
    
    
    183  | 
     | 
     | 
     | 
    
    
    184  | 
     | 
     | 
    /* counters */  | 
    
    
    185  | 
     | 
     | 
    int64_t npackets;		/* max packets to transmit */  | 
    
    
    186  | 
     | 
     | 
    int64_t nreceived;		/* # of packets we got back */  | 
    
    
    187  | 
     | 
     | 
    int64_t nrepeats;		/* number of duplicates */  | 
    
    
    188  | 
     | 
     | 
    int64_t ntransmitted;		/* sequence # for outbound packets = #sent */  | 
    
    
    189  | 
     | 
     | 
    int64_t nmissedmax = 1;		/* max value of ntransmitted - nreceived - 1 */  | 
    
    
    190  | 
     | 
     | 
    struct timeval interval = {1, 0}; /* interval between packets */ | 
    
    
    191  | 
     | 
     | 
     | 
    
    
    192  | 
     | 
     | 
    /* timing */  | 
    
    
    193  | 
     | 
     | 
    int timing = 0;			/* flag to do timing */  | 
    
    
    194  | 
     | 
     | 
    int timinginfo = 0;  | 
    
    
    195  | 
     | 
     | 
    unsigned int maxwait = MAXWAIT_DEFAULT;	/* max seconds to wait for response */  | 
    
    
    196  | 
     | 
     | 
    double tmin = 999999999.0;	/* minimum round trip time */  | 
    
    
    197  | 
     | 
     | 
    double tmax = 0.0;		/* maximum round trip time */  | 
    
    
    198  | 
     | 
     | 
    double tsum = 0.0;		/* sum of all times, for doing average */  | 
    
    
    199  | 
     | 
     | 
    double tsumsq = 0.0;		/* sum of all times squared, for std. dev. */  | 
    
    
    200  | 
     | 
     | 
     | 
    
    
    201  | 
     | 
     | 
    struct tv64 tv64_offset;  | 
    
    
    202  | 
     | 
     | 
    SIPHASH_KEY mac_key;  | 
    
    
    203  | 
     | 
     | 
     | 
    
    
    204  | 
     | 
     | 
    struct msghdr smsghdr;  | 
    
    
    205  | 
     | 
     | 
    struct iovec smsgiov;  | 
    
    
    206  | 
     | 
     | 
     | 
    
    
    207  | 
     | 
     | 
    volatile sig_atomic_t seenalrm;  | 
    
    
    208  | 
     | 
     | 
    volatile sig_atomic_t seenint;  | 
    
    
    209  | 
     | 
     | 
    volatile sig_atomic_t seeninfo;  | 
    
    
    210  | 
     | 
     | 
     | 
    
    
    211  | 
     | 
     | 
    void			 fill(char *, char *);  | 
    
    
    212  | 
     | 
     | 
    void			 summary(void);  | 
    
    
    213  | 
     | 
     | 
    void			 onsignal(int);  | 
    
    
    214  | 
     | 
     | 
    void			 retransmit(int);  | 
    
    
    215  | 
     | 
     | 
    int			 pinger(int);  | 
    
    
    216  | 
     | 
     | 
    const char		*pr_addr(struct sockaddr *, socklen_t);  | 
    
    
    217  | 
     | 
     | 
    void			 pr_pack(u_char *, int, struct msghdr *);  | 
    
    
    218  | 
     | 
     | 
    __dead void		 usage(void);  | 
    
    
    219  | 
     | 
     | 
     | 
    
    
    220  | 
     | 
     | 
    /* IPv4 specific functions */  | 
    
    
    221  | 
     | 
     | 
    void			 pr_ipopt(int, u_char *);  | 
    
    
    222  | 
     | 
     | 
    int			 in_cksum(u_short *, int);  | 
    
    
    223  | 
     | 
     | 
    void			 pr_icmph(struct icmp *);  | 
    
    
    224  | 
     | 
     | 
    void			 pr_retip(struct ip *);  | 
    
    
    225  | 
     | 
     | 
    void			 pr_iph(struct ip *);  | 
    
    
    226  | 
     | 
     | 
    #ifndef SMALL  | 
    
    
    227  | 
     | 
     | 
    int			 map_tos(char *, int *);  | 
    
    
    228  | 
     | 
     | 
    #endif	/* SMALL */  | 
    
    
    229  | 
     | 
     | 
     | 
    
    
    230  | 
     | 
     | 
    /* IPv6 specific functions */  | 
    
    
    231  | 
     | 
     | 
    int			 get_hoplim(struct msghdr *);  | 
    
    
    232  | 
     | 
     | 
    int			 get_pathmtu(struct msghdr *, struct sockaddr_in6 *);  | 
    
    
    233  | 
     | 
     | 
    void			 pr_icmph6(struct icmp6_hdr *, u_char *);  | 
    
    
    234  | 
     | 
     | 
    void			 pr_iph6(struct ip6_hdr *);  | 
    
    
    235  | 
     | 
     | 
    void			 pr_exthdrs(struct msghdr *);  | 
    
    
    236  | 
     | 
     | 
    void			 pr_ip6opt(void *);  | 
    
    
    237  | 
     | 
     | 
    void			 pr_rthdr(void *);  | 
    
    
    238  | 
     | 
     | 
    void			 pr_retip6(struct ip6_hdr *, u_char *);  | 
    
    
    239  | 
     | 
     | 
     | 
    
    
    240  | 
     | 
     | 
    int  | 
    
    
    241  | 
     | 
     | 
    main(int argc, char *argv[])  | 
    
    
    242  | 
     | 
     | 
    { | 
    
    
    243  | 
     | 
     | 
    	struct addrinfo hints, *res;  | 
    
    
    244  | 
     | 
     | 
    	struct itimerval itimer;  | 
    
    
    245  | 
     | 
     | 
    	struct sockaddr *from, *dst;  | 
    
    
    246  | 
     | 
     | 
    	struct sockaddr_in from4, dst4;  | 
    
    
    247  | 
     | 
     | 
    	struct sockaddr_in6 from6, dst6;  | 
    
    
    248  | 
     | 
     | 
    	struct cmsghdr *scmsg = NULL;  | 
    
    
    249  | 
     | 
     | 
    	struct in6_pktinfo *pktinfo = NULL;  | 
    
    
    250  | 
     | 
     | 
    	struct icmp6_filter filt;  | 
    
    
    251  | 
     | 
     | 
    	struct passwd *pw;  | 
    
    
    252  | 
     | 
     | 
    	socklen_t maxsizelen;  | 
    
    
    253  | 
     | 
     | 
    	int64_t preload;  | 
    
    
    254  | 
     | 
     | 
    	int ch, i, optval = 1, packlen, maxsize, error, s;  | 
    
    
    255  | 
     | 
     | 
    	int df = 0, tos = 0, bufspace = IP_MAXPACKET, hoplimit = -1, mflag = 0;  | 
    
    
    256  | 
     | 
     | 
    	u_char *datap, *packet;  | 
    
    
    257  | 
     | 
     | 
    	u_char ttl = MAXTTL;  | 
    
    
    258  | 
     | 
     | 
    	char *e, *target, hbuf[NI_MAXHOST], *source = NULL;  | 
    
    
    259  | 
     | 
     | 
    	char rspace[3 + 4 * NROUTES + 1];	/* record route space */  | 
    
    
    260  | 
     | 
     | 
    	const char *errstr;  | 
    
    
    261  | 
     | 
     | 
    	double intval;  | 
    
    
    262  | 
     | 
     | 
    	uid_t ouid, uid;  | 
    
    
    263  | 
     | 
     | 
    	gid_t gid;  | 
    
    
    264  | 
     | 
     | 
    	u_int rtableid = 0;  | 
    
    
    265  | 
     | 
     | 
    	extern char *__progname;  | 
    
    
    266  | 
     | 
     | 
     | 
    
    
    267  | 
     | 
     | 
    	if (strcmp("ping6", __progname) == 0) { | 
    
    
    268  | 
     | 
     | 
    		v6flag = 1;  | 
    
    
    269  | 
     | 
     | 
    		maxpayload = MAXPAYLOAD6;  | 
    
    
    270  | 
     | 
     | 
    		if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)  | 
    
    
    271  | 
     | 
     | 
    			err(1, "socket");  | 
    
    
    272  | 
     | 
     | 
    	} else { | 
    
    
    273  | 
     | 
     | 
    		if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)  | 
    
    
    274  | 
     | 
     | 
    			err(1, "socket");  | 
    
    
    275  | 
     | 
     | 
    	}  | 
    
    
    276  | 
     | 
     | 
     | 
    
    
    277  | 
     | 
     | 
    	/* revoke privs */  | 
    
    
    278  | 
     | 
     | 
    	ouid = getuid();  | 
    
    
    279  | 
     | 
     | 
    	if (ouid == 0 && (pw = getpwnam(PING_USER)) != NULL) { | 
    
    
    280  | 
     | 
     | 
    		uid = pw->pw_uid;  | 
    
    
    281  | 
     | 
     | 
    		gid = pw->pw_gid;  | 
    
    
    282  | 
     | 
     | 
    	} else { | 
    
    
    283  | 
     | 
     | 
    		uid = getuid();  | 
    
    
    284  | 
     | 
     | 
    		gid = getgid();  | 
    
    
    285  | 
     | 
     | 
    	}  | 
    
    
    286  | 
     | 
     | 
    	if (setgroups(1, &gid) ||  | 
    
    
    287  | 
     | 
     | 
    	    setresgid(gid, gid, gid) ||  | 
    
    
    288  | 
     | 
     | 
    	    setresuid(uid, uid, uid))  | 
    
    
    289  | 
     | 
     | 
    		err(1, "unable to revoke privs");  | 
    
    
    290  | 
     | 
     | 
     | 
    
    
    291  | 
     | 
     | 
    	preload = 0;  | 
    
    
    292  | 
     | 
     | 
    	datap = &outpack[ECHOLEN + ECHOTMLEN];  | 
    
    
    293  | 
     | 
     | 
    	while ((ch = getopt(argc, argv, v6flag ?  | 
    
    
    294  | 
     | 
     | 
    	    "c:dEefHh:I:i:Ll:mNnp:qS:s:V:vw:" :  | 
    
    
    295  | 
     | 
     | 
    	    "DEI:LRS:c:defHi:l:np:qs:T:t:V:vw:")) != -1) { | 
    
    
    296  | 
     | 
     | 
    		switch(ch) { | 
    
    
    297  | 
     | 
     | 
    		case 'c':  | 
    
    
    298  | 
     | 
     | 
    			npackets = strtonum(optarg, 0, INT64_MAX, &errstr);  | 
    
    
    299  | 
     | 
     | 
    			if (errstr)  | 
    
    
    300  | 
     | 
     | 
    				errx(1,  | 
    
    
    301  | 
     | 
     | 
    				    "number of packets to transmit is %s: %s",  | 
    
    
    302  | 
     | 
     | 
    				    errstr, optarg);  | 
    
    
    303  | 
     | 
     | 
    			break;  | 
    
    
    304  | 
     | 
     | 
    		case 'D':  | 
    
    
    305  | 
     | 
     | 
    			options |= F_HDRINCL;  | 
    
    
    306  | 
     | 
     | 
    			df = 1;  | 
    
    
    307  | 
     | 
     | 
    			break;  | 
    
    
    308  | 
     | 
     | 
    		case 'd':  | 
    
    
    309  | 
     | 
     | 
    			options |= F_SO_DEBUG;  | 
    
    
    310  | 
     | 
     | 
    			break;  | 
    
    
    311  | 
     | 
     | 
    		case 'E':  | 
    
    
    312  | 
     | 
     | 
    			options |= F_AUD_MISS;  | 
    
    
    313  | 
     | 
     | 
    			break;  | 
    
    
    314  | 
     | 
     | 
    		case 'e':  | 
    
    
    315  | 
     | 
     | 
    			options |= F_AUD_RECV;  | 
    
    
    316  | 
     | 
     | 
    			break;  | 
    
    
    317  | 
     | 
     | 
    		case 'f':  | 
    
    
    318  | 
     | 
     | 
    			if (ouid)  | 
    
    
    319  | 
     | 
     | 
    				errc(1, EPERM, NULL);  | 
    
    
    320  | 
     | 
     | 
    			options |= F_FLOOD;  | 
    
    
    321  | 
     | 
     | 
    			setvbuf(stdout, NULL, _IONBF, 0);  | 
    
    
    322  | 
     | 
     | 
    			break;  | 
    
    
    323  | 
     | 
     | 
    		case 'H':  | 
    
    
    324  | 
     | 
     | 
    			options |= F_HOSTNAME;  | 
    
    
    325  | 
     | 
     | 
    			break;  | 
    
    
    326  | 
     | 
     | 
    		case 'h':		/* hoplimit */  | 
    
    
    327  | 
     | 
     | 
    			hoplimit = strtonum(optarg, 0, IPV6_MAXHLIM, &errstr);  | 
    
    
    328  | 
     | 
     | 
    			if (errstr)  | 
    
    
    329  | 
     | 
     | 
    				errx(1, "hoplimit is %s: %s", errstr, optarg);  | 
    
    
    330  | 
     | 
     | 
    			break;  | 
    
    
    331  | 
     | 
     | 
    		case 'I':  | 
    
    
    332  | 
     | 
     | 
    		case 'S':	/* deprecated */  | 
    
    
    333  | 
     | 
     | 
    			source = optarg;  | 
    
    
    334  | 
     | 
     | 
    			break;  | 
    
    
    335  | 
     | 
     | 
    		case 'i':		/* wait between sending packets */  | 
    
    
    336  | 
     | 
     | 
    			intval = strtod(optarg, &e);  | 
    
    
    337  | 
     | 
     | 
    			if (*optarg == '\0' || *e != '\0')  | 
    
    
    338  | 
     | 
     | 
    				errx(1, "illegal timing interval %s", optarg);  | 
    
    
    339  | 
     | 
     | 
    			if (intval < 1 && ouid)  | 
    
    
    340  | 
     | 
     | 
    				errx(1, "only root may use interval < 1s");  | 
    
    
    341  | 
     | 
     | 
    			interval.tv_sec = (time_t)intval;  | 
    
    
    342  | 
     | 
     | 
    			interval.tv_usec =  | 
    
    
    343  | 
     | 
     | 
    			    (long)((intval - interval.tv_sec) * 1000000);  | 
    
    
    344  | 
     | 
     | 
    			if (interval.tv_sec < 0)  | 
    
    
    345  | 
     | 
     | 
    				errx(1, "illegal timing interval %s", optarg);  | 
    
    
    346  | 
     | 
     | 
    			/* less than 1/Hz does not make sense */  | 
    
    
    347  | 
     | 
     | 
    			if (interval.tv_sec == 0 && interval.tv_usec < 10000) { | 
    
    
    348  | 
     | 
     | 
    				warnx("too small interval, raised to 0.01"); | 
    
    
    349  | 
     | 
     | 
    				interval.tv_usec = 10000;  | 
    
    
    350  | 
     | 
     | 
    			}  | 
    
    
    351  | 
     | 
     | 
    			options |= F_INTERVAL;  | 
    
    
    352  | 
     | 
     | 
    			break;  | 
    
    
    353  | 
     | 
     | 
    		case 'L':  | 
    
    
    354  | 
     | 
     | 
    			moptions |= MULTICAST_NOLOOP;  | 
    
    
    355  | 
     | 
     | 
    			break;  | 
    
    
    356  | 
     | 
     | 
    		case 'l':  | 
    
    
    357  | 
     | 
     | 
    			if (ouid)  | 
    
    
    358  | 
     | 
     | 
    				errc(1, EPERM, NULL);  | 
    
    
    359  | 
     | 
     | 
    			preload = strtonum(optarg, 1, INT64_MAX, &errstr);  | 
    
    
    360  | 
     | 
     | 
    			if (errstr)  | 
    
    
    361  | 
     | 
     | 
    				errx(1, "preload value is %s: %s", errstr,  | 
    
    
    362  | 
     | 
     | 
    				    optarg);  | 
    
    
    363  | 
     | 
     | 
    			break;  | 
    
    
    364  | 
     | 
     | 
    		case 'm':  | 
    
    
    365  | 
     | 
     | 
    			mflag++;  | 
    
    
    366  | 
     | 
     | 
    			break;  | 
    
    
    367  | 
     | 
     | 
    		case 'n':  | 
    
    
    368  | 
     | 
     | 
    			options &= ~F_HOSTNAME;  | 
    
    
    369  | 
     | 
     | 
    			break;  | 
    
    
    370  | 
     | 
     | 
    		case 'p':		/* fill buffer with user pattern */  | 
    
    
    371  | 
     | 
     | 
    			options |= F_PINGFILLED;  | 
    
    
    372  | 
     | 
     | 
    			fill((char *)datap, optarg);  | 
    
    
    373  | 
     | 
     | 
    				break;  | 
    
    
    374  | 
     | 
     | 
    		case 'q':  | 
    
    
    375  | 
     | 
     | 
    			options |= F_QUIET;  | 
    
    
    376  | 
     | 
     | 
    			break;  | 
    
    
    377  | 
     | 
     | 
    		case 'R':  | 
    
    
    378  | 
     | 
     | 
    			options |= F_RROUTE;  | 
    
    
    379  | 
     | 
     | 
    			break;  | 
    
    
    380  | 
     | 
     | 
    		case 's':		/* size of packet to send */  | 
    
    
    381  | 
     | 
     | 
    			datalen = strtonum(optarg, 0, maxpayload, &errstr);  | 
    
    
    382  | 
     | 
     | 
    			if (errstr)  | 
    
    
    383  | 
     | 
     | 
    				errx(1, "packet size is %s: %s", errstr,  | 
    
    
    384  | 
     | 
     | 
    				    optarg);  | 
    
    
    385  | 
     | 
     | 
    			break;  | 
    
    
    386  | 
     | 
     | 
    #ifndef SMALL  | 
    
    
    387  | 
     | 
     | 
    		case 'T':  | 
    
    
    388  | 
     | 
     | 
    			options |= F_HDRINCL;  | 
    
    
    389  | 
     | 
     | 
    			errno = 0;  | 
    
    
    390  | 
     | 
     | 
    			errstr = NULL;  | 
    
    
    391  | 
     | 
     | 
    			if (map_tos(optarg, &tos))  | 
    
    
    392  | 
     | 
     | 
    				break;  | 
    
    
    393  | 
     | 
     | 
    			if (strlen(optarg) > 1 && optarg[0] == '0' &&  | 
    
    
    394  | 
     | 
     | 
    			    optarg[1] == 'x')  | 
    
    
    395  | 
     | 
     | 
    				tos = (int)strtol(optarg, NULL, 16);  | 
    
    
    396  | 
     | 
     | 
    			else  | 
    
    
    397  | 
     | 
     | 
    				tos = strtonum(optarg, 0, 255, &errstr);  | 
    
    
    398  | 
     | 
     | 
    			if (tos < 0 || tos > 255 || errstr || errno)  | 
    
    
    399  | 
     | 
     | 
    				errx(1, "illegal tos value %s", optarg);  | 
    
    
    400  | 
     | 
     | 
    			break;  | 
    
    
    401  | 
     | 
     | 
    #endif	/* SMALL */  | 
    
    
    402  | 
     | 
     | 
    		case 't':  | 
    
    
    403  | 
     | 
     | 
    			options |= F_TTL;  | 
    
    
    404  | 
     | 
     | 
    			ttl = strtonum(optarg, 0, MAXTTL, &errstr);  | 
    
    
    405  | 
     | 
     | 
    			if (errstr)  | 
    
    
    406  | 
     | 
     | 
    				errx(1, "ttl value is %s: %s", errstr, optarg);  | 
    
    
    407  | 
     | 
     | 
    			break;  | 
    
    
    408  | 
     | 
     | 
    		case 'V':  | 
    
    
    409  | 
     | 
     | 
    			rtableid = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr);  | 
    
    
    410  | 
     | 
     | 
    			if (errstr)  | 
    
    
    411  | 
     | 
     | 
    				errx(1, "rtable value is %s: %s", errstr,  | 
    
    
    412  | 
     | 
     | 
    				    optarg);  | 
    
    
    413  | 
     | 
     | 
    			if (setsockopt(s, SOL_SOCKET, SO_RTABLE, &rtableid,  | 
    
    
    414  | 
     | 
     | 
    			    sizeof(rtableid)) == -1)  | 
    
    
    415  | 
     | 
     | 
    				err(1, "setsockopt SO_RTABLE");  | 
    
    
    416  | 
     | 
     | 
    			break;  | 
    
    
    417  | 
     | 
     | 
    		case 'v':  | 
    
    
    418  | 
     | 
     | 
    			options |= F_VERBOSE;  | 
    
    
    419  | 
     | 
     | 
    			break;  | 
    
    
    420  | 
     | 
     | 
    		case 'w':  | 
    
    
    421  | 
     | 
     | 
    			maxwait = strtonum(optarg, 1, INT_MAX, &errstr);  | 
    
    
    422  | 
     | 
     | 
    			if (errstr)  | 
    
    
    423  | 
     | 
     | 
    				errx(1, "maxwait value is %s: %s",  | 
    
    
    424  | 
     | 
     | 
    				    errstr, optarg);  | 
    
    
    425  | 
     | 
     | 
    			break;  | 
    
    
    426  | 
     | 
     | 
    		default:  | 
    
    
    427  | 
     | 
     | 
    			usage();  | 
    
    
    428  | 
     | 
     | 
    		}  | 
    
    
    429  | 
     | 
     | 
    	}  | 
    
    
    430  | 
     | 
     | 
     | 
    
    
    431  | 
     | 
     | 
    	argc -= optind;  | 
    
    
    432  | 
     | 
     | 
    	argv += optind;  | 
    
    
    433  | 
     | 
     | 
     | 
    
    
    434  | 
     | 
     | 
    	if (argc != 1)  | 
    
    
    435  | 
     | 
     | 
    		usage();  | 
    
    
    436  | 
     | 
     | 
     | 
    
    
    437  | 
     | 
     | 
    	memset(&dst4, 0, sizeof(dst4));  | 
    
    
    438  | 
     | 
     | 
    	memset(&dst6, 0, sizeof(dst6));  | 
    
    
    439  | 
     | 
     | 
     | 
    
    
    440  | 
     | 
     | 
    	target = *argv;  | 
    
    
    441  | 
     | 
     | 
     | 
    
    
    442  | 
     | 
     | 
    	memset(&hints, 0, sizeof(hints));  | 
    
    
    443  | 
     | 
     | 
    	hints.ai_family = v6flag ? AF_INET6 : AF_INET;  | 
    
    
    444  | 
     | 
     | 
    	hints.ai_socktype = SOCK_RAW;  | 
    
    
    445  | 
     | 
     | 
    	hints.ai_protocol = 0;  | 
    
    
    446  | 
     | 
     | 
    	hints.ai_flags = AI_CANONNAME;  | 
    
    
    447  | 
     | 
     | 
    	if ((error = getaddrinfo(target, NULL, &hints, &res)))  | 
    
    
    448  | 
     | 
     | 
    		errx(1, "%s", gai_strerror(error));  | 
    
    
    449  | 
     | 
     | 
     | 
    
    
    450  | 
     | 
     | 
    	switch (res->ai_family) { | 
    
    
    451  | 
     | 
     | 
    	case AF_INET:  | 
    
    
    452  | 
     | 
     | 
    		if (res->ai_addrlen != sizeof(dst4))  | 
    
    
    453  | 
     | 
     | 
    			errx(1, "size of sockaddr mismatch");  | 
    
    
    454  | 
     | 
     | 
    		dst = (struct sockaddr *)&dst4;  | 
    
    
    455  | 
     | 
     | 
    		from = (struct sockaddr *)&from4;  | 
    
    
    456  | 
     | 
     | 
    		break;  | 
    
    
    457  | 
     | 
     | 
    	case AF_INET6:  | 
    
    
    458  | 
     | 
     | 
    		if (res->ai_addrlen != sizeof(dst6))  | 
    
    
    459  | 
     | 
     | 
    			errx(1, "size of sockaddr mismatch");  | 
    
    
    460  | 
     | 
     | 
    		dst = (struct sockaddr *)&dst6;  | 
    
    
    461  | 
     | 
     | 
    		from = (struct sockaddr *)&from6;  | 
    
    
    462  | 
     | 
     | 
    		break;  | 
    
    
    463  | 
     | 
     | 
    	default:  | 
    
    
    464  | 
     | 
     | 
    		errx(1, "unsupported AF: %d", res->ai_family);  | 
    
    
    465  | 
     | 
     | 
    		break;  | 
    
    
    466  | 
     | 
     | 
    	}  | 
    
    
    467  | 
     | 
     | 
     | 
    
    
    468  | 
     | 
     | 
    	memcpy(dst, res->ai_addr, res->ai_addrlen);  | 
    
    
    469  | 
     | 
     | 
     | 
    
    
    470  | 
     | 
     | 
    	if (!hostname) { | 
    
    
    471  | 
     | 
     | 
    		hostname = res->ai_canonname ? strdup(res->ai_canonname) :  | 
    
    
    472  | 
     | 
     | 
    		    target;  | 
    
    
    473  | 
     | 
     | 
    		if (!hostname)  | 
    
    
    474  | 
     | 
     | 
    			err(1, "malloc");  | 
    
    
    475  | 
     | 
     | 
    	}  | 
    
    
    476  | 
     | 
     | 
     | 
    
    
    477  | 
     | 
     | 
    	if (res->ai_next) { | 
    
    
    478  | 
     | 
     | 
    		if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,  | 
    
    
    479  | 
     | 
     | 
    		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)  | 
    
    
    480  | 
     | 
     | 
    			strlcpy(hbuf, "?", sizeof(hbuf));  | 
    
    
    481  | 
     | 
     | 
    		warnx("Warning: %s has multiple " | 
    
    
    482  | 
     | 
     | 
    		    "addresses; using %s", hostname, hbuf);  | 
    
    
    483  | 
     | 
     | 
    	}  | 
    
    
    484  | 
     | 
     | 
    	freeaddrinfo(res);  | 
    
    
    485  | 
     | 
     | 
     | 
    
    
    486  | 
     | 
     | 
    	if (source) { | 
    
    
    487  | 
     | 
     | 
    		memset(&hints, 0, sizeof(hints));  | 
    
    
    488  | 
     | 
     | 
    		hints.ai_family = dst->sa_family;  | 
    
    
    489  | 
     | 
     | 
    		if ((error = getaddrinfo(source, NULL, &hints, &res)))  | 
    
    
    490  | 
     | 
     | 
    			errx(1, "%s: %s", source, gai_strerror(error));  | 
    
    
    491  | 
     | 
     | 
    		if (res->ai_addrlen != dst->sa_len)  | 
    
    
    492  | 
     | 
     | 
    			errx(1, "size of sockaddr mismatch");  | 
    
    
    493  | 
     | 
     | 
    		memcpy(from, res->ai_addr, res->ai_addrlen);  | 
    
    
    494  | 
     | 
     | 
    		freeaddrinfo(res);  | 
    
    
    495  | 
     | 
     | 
     | 
    
    
    496  | 
     | 
     | 
    		if (!v6flag && IN_MULTICAST(ntohl(dst4.sin_addr.s_addr))) { | 
    
    
    497  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,  | 
    
    
    498  | 
     | 
     | 
    			    &from4.sin_addr, sizeof(from4.sin_addr)) < 0)  | 
    
    
    499  | 
     | 
     | 
    				err(1, "setsockopt IP_MULTICAST_IF");  | 
    
    
    500  | 
     | 
     | 
    		} else { | 
    
    
    501  | 
     | 
     | 
    			if (bind(s, from, from->sa_len) < 0)  | 
    
    
    502  | 
     | 
     | 
    				err(1, "bind");  | 
    
    
    503  | 
     | 
     | 
    		}  | 
    
    
    504  | 
     | 
     | 
    	} else if (options & F_VERBOSE) { | 
    
    
    505  | 
     | 
     | 
    		/*  | 
    
    
    506  | 
     | 
     | 
    		 * get the source address. XXX since we revoked the root  | 
    
    
    507  | 
     | 
     | 
    		 * privilege, we cannot use a raw socket for this.  | 
    
    
    508  | 
     | 
     | 
    		 */  | 
    
    
    509  | 
     | 
     | 
    		int dummy;  | 
    
    
    510  | 
     | 
     | 
    		socklen_t len = dst->sa_len;  | 
    
    
    511  | 
     | 
     | 
     | 
    
    
    512  | 
     | 
     | 
    		if ((dummy = socket(dst->sa_family, SOCK_DGRAM, 0)) < 0)  | 
    
    
    513  | 
     | 
     | 
    			err(1, "UDP socket");  | 
    
    
    514  | 
     | 
     | 
     | 
    
    
    515  | 
     | 
     | 
    		memcpy(from, dst, dst->sa_len);  | 
    
    
    516  | 
     | 
     | 
    		if (v6flag) { | 
    
    
    517  | 
     | 
     | 
    			from6.sin6_port = ntohs(DUMMY_PORT);  | 
    
    
    518  | 
     | 
     | 
    			if (pktinfo &&  | 
    
    
    519  | 
     | 
     | 
    			    setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,  | 
    
    
    520  | 
     | 
     | 
    			    (void *)pktinfo, sizeof(*pktinfo)))  | 
    
    
    521  | 
     | 
     | 
    				err(1, "UDP setsockopt(IPV6_PKTINFO)");  | 
    
    
    522  | 
     | 
     | 
     | 
    
    
    523  | 
     | 
     | 
    			if (hoplimit != -1 &&  | 
    
    
    524  | 
     | 
     | 
    			    setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,  | 
    
    
    525  | 
     | 
     | 
    			    (void *)&hoplimit, sizeof(hoplimit)))  | 
    
    
    526  | 
     | 
     | 
    				err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");  | 
    
    
    527  | 
     | 
     | 
     | 
    
    
    528  | 
     | 
     | 
    			if (hoplimit != -1 &&  | 
    
    
    529  | 
     | 
     | 
    			    setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,  | 
    
    
    530  | 
     | 
     | 
    			    (void *)&hoplimit, sizeof(hoplimit)))  | 
    
    
    531  | 
     | 
     | 
    				err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");  | 
    
    
    532  | 
     | 
     | 
    		} else { | 
    
    
    533  | 
     | 
     | 
    			u_char loop = 0;  | 
    
    
    534  | 
     | 
     | 
     | 
    
    
    535  | 
     | 
     | 
    			from4.sin_port = ntohs(DUMMY_PORT);  | 
    
    
    536  | 
     | 
     | 
     | 
    
    
    537  | 
     | 
     | 
    			if ((moptions & MULTICAST_NOLOOP) && setsockopt(dummy,  | 
    
    
    538  | 
     | 
     | 
    			    IPPROTO_IP, IP_MULTICAST_LOOP, &loop,  | 
    
    
    539  | 
     | 
     | 
    			    sizeof(loop)) < 0)  | 
    
    
    540  | 
     | 
     | 
    				err(1, "setsockopt IP_MULTICAST_LOOP");  | 
    
    
    541  | 
     | 
     | 
    			if ((moptions & MULTICAST_TTL) && setsockopt(dummy,  | 
    
    
    542  | 
     | 
     | 
    			    IPPROTO_IP, IP_MULTICAST_TTL, &ttl,  | 
    
    
    543  | 
     | 
     | 
    			    sizeof(ttl)) < 0)  | 
    
    
    544  | 
     | 
     | 
    				err(1, "setsockopt IP_MULTICAST_TTL");  | 
    
    
    545  | 
     | 
     | 
    		}  | 
    
    
    546  | 
     | 
     | 
     | 
    
    
    547  | 
     | 
     | 
    		if (rtableid > 0 &&  | 
    
    
    548  | 
     | 
     | 
    		    setsockopt(dummy, SOL_SOCKET, SO_RTABLE, &rtableid,  | 
    
    
    549  | 
     | 
     | 
    		    sizeof(rtableid)) < 0)  | 
    
    
    550  | 
     | 
     | 
    			err(1, "setsockopt(SO_RTABLE)");  | 
    
    
    551  | 
     | 
     | 
     | 
    
    
    552  | 
     | 
     | 
    		if (connect(dummy, from, len) < 0)  | 
    
    
    553  | 
     | 
     | 
    			err(1, "UDP connect");  | 
    
    
    554  | 
     | 
     | 
     | 
    
    
    555  | 
     | 
     | 
    		if (getsockname(dummy, from, &len) < 0)  | 
    
    
    556  | 
     | 
     | 
    			err(1, "getsockname");  | 
    
    
    557  | 
     | 
     | 
     | 
    
    
    558  | 
     | 
     | 
    		close(dummy);  | 
    
    
    559  | 
     | 
     | 
    	}  | 
    
    
    560  | 
     | 
     | 
     | 
    
    
    561  | 
     | 
     | 
    	if (options & F_SO_DEBUG)  | 
    
    
    562  | 
     | 
     | 
    		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, &optval,  | 
    
    
    563  | 
     | 
     | 
    		    sizeof(optval));  | 
    
    
    564  | 
     | 
     | 
     | 
    
    
    565  | 
     | 
     | 
    	if ((options & F_FLOOD) && (options & F_INTERVAL))  | 
    
    
    566  | 
     | 
     | 
    		errx(1, "-f and -i options are incompatible");  | 
    
    
    567  | 
     | 
     | 
     | 
    
    
    568  | 
     | 
     | 
    	if ((options & F_FLOOD) && (options & (F_AUD_RECV | F_AUD_MISS)))  | 
    
    
    569  | 
     | 
     | 
    		warnx("No audible output for flood pings"); | 
    
    
    570  | 
     | 
     | 
     | 
    
    
    571  | 
     | 
     | 
    	if (datalen >= sizeof(struct payload))	/* can we time transfer */  | 
    
    
    572  | 
     | 
     | 
    		timing = 1;  | 
    
    
    573  | 
     | 
     | 
     | 
    
    
    574  | 
     | 
     | 
    	if (v6flag) { | 
    
    
    575  | 
     | 
     | 
    		/* in F_VERBOSE case, we may get non-echoreply packets*/  | 
    
    
    576  | 
     | 
     | 
    		if ((options & F_VERBOSE) && datalen < 2048) /* XXX 2048? */  | 
    
    
    577  | 
     | 
     | 
    			packlen = 2048 + IP6LEN + ECHOLEN + EXTRA;  | 
    
    
    578  | 
     | 
     | 
    		else  | 
    
    
    579  | 
     | 
     | 
    			packlen = datalen + IP6LEN + ECHOLEN + EXTRA;  | 
    
    
    580  | 
     | 
     | 
    	} else  | 
    
    
    581  | 
     | 
     | 
    		packlen = datalen + MAXIPLEN + MAXICMPLEN;  | 
    
    
    582  | 
     | 
     | 
    	if (!(packet = malloc(packlen)))  | 
    
    
    583  | 
     | 
     | 
    		err(1, "malloc");  | 
    
    
    584  | 
     | 
     | 
     | 
    
    
    585  | 
     | 
     | 
    	if (!(options & F_PINGFILLED))  | 
    
    
    586  | 
     | 
     | 
    		for (i = ECHOTMLEN; i < datalen; ++i)  | 
    
    
    587  | 
     | 
     | 
    			*datap++ = i;  | 
    
    
    588  | 
     | 
     | 
     | 
    
    
    589  | 
     | 
     | 
    	ident = getpid() & 0xFFFF;  | 
    
    
    590  | 
     | 
     | 
     | 
    
    
    591  | 
     | 
     | 
    	/*  | 
    
    
    592  | 
     | 
     | 
    	 * When trying to send large packets, you must increase the  | 
    
    
    593  | 
     | 
     | 
    	 * size of both the send and receive buffers...  | 
    
    
    594  | 
     | 
     | 
    	 */  | 
    
    
    595  | 
     | 
     | 
    	maxsizelen = sizeof maxsize;  | 
    
    
    596  | 
     | 
     | 
    	if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &maxsize, &maxsizelen) < 0)  | 
    
    
    597  | 
     | 
     | 
    		err(1, "getsockopt");  | 
    
    
    598  | 
     | 
     | 
    	if (maxsize < packlen &&  | 
    
    
    599  | 
     | 
     | 
    	    setsockopt(s, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(maxsize)) < 0)  | 
    
    
    600  | 
     | 
     | 
    		err(1, "setsockopt");  | 
    
    
    601  | 
     | 
     | 
     | 
    
    
    602  | 
     | 
     | 
    	/*  | 
    
    
    603  | 
     | 
     | 
    	 * When pinging the broadcast address, you can get a lot of answers.  | 
    
    
    604  | 
     | 
     | 
    	 * Doing something so evil is useful if you are trying to stress the  | 
    
    
    605  | 
     | 
     | 
    	 * ethernet, or just want to fill the arp cache to get some stuff for  | 
    
    
    606  | 
     | 
     | 
    	 * /etc/ethers.  | 
    
    
    607  | 
     | 
     | 
    	 */  | 
    
    
    608  | 
     | 
     | 
    	while (setsockopt(s, SOL_SOCKET, SO_RCVBUF,  | 
    
    
    609  | 
     | 
     | 
    	    (void*)&bufspace, sizeof(bufspace)) < 0) { | 
    
    
    610  | 
     | 
     | 
    		if ((bufspace -= 1024) <= 0)  | 
    
    
    611  | 
     | 
     | 
    			err(1, "Cannot set the receive buffer size");  | 
    
    
    612  | 
     | 
     | 
    	}  | 
    
    
    613  | 
     | 
     | 
    	if (bufspace < IP_MAXPACKET)  | 
    
    
    614  | 
     | 
     | 
    		warnx("Could only allocate a receive buffer of %d bytes " | 
    
    
    615  | 
     | 
     | 
    		    "(default %d)", bufspace, IP_MAXPACKET);  | 
    
    
    616  | 
     | 
     | 
     | 
    
    
    617  | 
     | 
     | 
    	if (v6flag) { | 
    
    
    618  | 
     | 
     | 
    		unsigned int loop = 0;  | 
    
    
    619  | 
     | 
     | 
     | 
    
    
    620  | 
     | 
     | 
    		/*  | 
    
    
    621  | 
     | 
     | 
    		 * let the kernel pass extension headers of incoming packets,  | 
    
    
    622  | 
     | 
     | 
    		 * for privileged socket options  | 
    
    
    623  | 
     | 
     | 
    		 */  | 
    
    
    624  | 
     | 
     | 
    		if (options & F_VERBOSE) { | 
    
    
    625  | 
     | 
     | 
    			int opton = 1;  | 
    
    
    626  | 
     | 
     | 
     | 
    
    
    627  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS,  | 
    
    
    628  | 
     | 
     | 
    			    &opton, (socklen_t)sizeof(opton)))  | 
    
    
    629  | 
     | 
     | 
    				err(1, "setsockopt(IPV6_RECVHOPOPTS)");  | 
    
    
    630  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS,  | 
    
    
    631  | 
     | 
     | 
    			    &opton, (socklen_t)sizeof(opton)))  | 
    
    
    632  | 
     | 
     | 
    				err(1, "setsockopt(IPV6_RECVDSTOPTS)");  | 
    
    
    633  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,  | 
    
    
    634  | 
     | 
     | 
    			    sizeof(opton)))  | 
    
    
    635  | 
     | 
     | 
    				err(1, "setsockopt(IPV6_RECVRTHDR)");  | 
    
    
    636  | 
     | 
     | 
    			ICMP6_FILTER_SETPASSALL(&filt);  | 
    
    
    637  | 
     | 
     | 
    		} else { | 
    
    
    638  | 
     | 
     | 
    			ICMP6_FILTER_SETBLOCKALL(&filt);  | 
    
    
    639  | 
     | 
     | 
    			ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);  | 
    
    
    640  | 
     | 
     | 
    		}  | 
    
    
    641  | 
     | 
     | 
     | 
    
    
    642  | 
     | 
     | 
    		if ((moptions & MULTICAST_NOLOOP) &&  | 
    
    
    643  | 
     | 
     | 
    		    setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop,  | 
    
    
    644  | 
     | 
     | 
    		    sizeof(loop)) < 0)  | 
    
    
    645  | 
     | 
     | 
    			err(1, "setsockopt IPV6_MULTICAST_LOOP");  | 
    
    
    646  | 
     | 
     | 
     | 
    
    
    647  | 
     | 
     | 
    		optval = IPV6_DEFHLIM;  | 
    
    
    648  | 
     | 
     | 
    		if (IN6_IS_ADDR_MULTICAST(&dst6.sin6_addr))  | 
    
    
    649  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,  | 
    
    
    650  | 
     | 
     | 
    			    &optval, (socklen_t)sizeof(optval)) == -1)  | 
    
    
    651  | 
     | 
     | 
    				err(1, "IPV6_MULTICAST_HOPS");  | 
    
    
    652  | 
     | 
     | 
    		if (mflag != 1) { | 
    
    
    653  | 
     | 
     | 
    			optval = mflag > 1 ? 0 : 1;  | 
    
    
    654  | 
     | 
     | 
     | 
    
    
    655  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,  | 
    
    
    656  | 
     | 
     | 
    			    &optval, (socklen_t)sizeof(optval)) == -1)  | 
    
    
    657  | 
     | 
     | 
    				err(1, "setsockopt(IPV6_USE_MIN_MTU)");  | 
    
    
    658  | 
     | 
     | 
    		} else { | 
    
    
    659  | 
     | 
     | 
    			optval = 1;  | 
    
    
    660  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU,  | 
    
    
    661  | 
     | 
     | 
    			    &optval, sizeof(optval)) == -1)  | 
    
    
    662  | 
     | 
     | 
    				err(1, "setsockopt(IPV6_RECVPATHMTU)");  | 
    
    
    663  | 
     | 
     | 
    		}  | 
    
    
    664  | 
     | 
     | 
     | 
    
    
    665  | 
     | 
     | 
    		if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,  | 
    
    
    666  | 
     | 
     | 
    		    (socklen_t)sizeof(filt)) < 0)  | 
    
    
    667  | 
     | 
     | 
    			err(1, "setsockopt(ICMP6_FILTER)");  | 
    
    
    668  | 
     | 
     | 
     | 
    
    
    669  | 
     | 
     | 
    		if (hoplimit != -1) { | 
    
    
    670  | 
     | 
     | 
    			/* set IP6 packet options */  | 
    
    
    671  | 
     | 
     | 
    			if ((scmsg = malloc( CMSG_SPACE(sizeof(int)))) == NULL)  | 
    
    
    672  | 
     | 
     | 
    				err(1, "malloc");  | 
    
    
    673  | 
     | 
     | 
    			smsghdr.msg_control = (caddr_t)scmsg;  | 
    
    
    674  | 
     | 
     | 
    			smsghdr.msg_controllen = CMSG_SPACE(sizeof(int));  | 
    
    
    675  | 
     | 
     | 
     | 
    
    
    676  | 
     | 
     | 
    			scmsg->cmsg_len = CMSG_LEN(sizeof(int));  | 
    
    
    677  | 
     | 
     | 
    			scmsg->cmsg_level = IPPROTO_IPV6;  | 
    
    
    678  | 
     | 
     | 
    			scmsg->cmsg_type = IPV6_HOPLIMIT;  | 
    
    
    679  | 
     | 
     | 
    			*(int *)(CMSG_DATA(scmsg)) = hoplimit;  | 
    
    
    680  | 
     | 
     | 
    		}  | 
    
    
    681  | 
     | 
     | 
     | 
    
    
    682  | 
     | 
     | 
    		optval = 1;  | 
    
    
    683  | 
     | 
     | 
    		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval,  | 
    
    
    684  | 
     | 
     | 
    		    (socklen_t)sizeof(optval)) < 0)  | 
    
    
    685  | 
     | 
     | 
    			warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ | 
    
    
    686  | 
     | 
     | 
    		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval,  | 
    
    
    687  | 
     | 
     | 
    		    (socklen_t)sizeof(optval)) < 0)  | 
    
    
    688  | 
     | 
     | 
    			warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ | 
    
    
    689  | 
     | 
     | 
    	} else { | 
    
    
    690  | 
     | 
     | 
    		u_char loop = 0;  | 
    
    
    691  | 
     | 
     | 
     | 
    
    
    692  | 
     | 
     | 
    		if (options & F_TTL) { | 
    
    
    693  | 
     | 
     | 
    			if (IN_MULTICAST(ntohl(dst4.sin_addr.s_addr)))  | 
    
    
    694  | 
     | 
     | 
    				moptions |= MULTICAST_TTL;  | 
    
    
    695  | 
     | 
     | 
    			else  | 
    
    
    696  | 
     | 
     | 
    				options |= F_HDRINCL;  | 
    
    
    697  | 
     | 
     | 
    		}  | 
    
    
    698  | 
     | 
     | 
     | 
    
    
    699  | 
     | 
     | 
    		if ((options & F_RROUTE) && (options & F_HDRINCL))  | 
    
    
    700  | 
     | 
     | 
    			errx(1, "-R option and -D or -T, or -t to unicast"  | 
    
    
    701  | 
     | 
     | 
    			    " destinations are incompatible");  | 
    
    
    702  | 
     | 
     | 
     | 
    
    
    703  | 
     | 
     | 
    		if (options & F_HDRINCL) { | 
    
    
    704  | 
     | 
     | 
    			struct ip *ip = (struct ip *)outpackhdr;  | 
    
    
    705  | 
     | 
     | 
     | 
    
    
    706  | 
     | 
     | 
    			setsockopt(s, IPPROTO_IP, IP_HDRINCL, &optval,  | 
    
    
    707  | 
     | 
     | 
    			    sizeof(optval));  | 
    
    
    708  | 
     | 
     | 
    			ip->ip_v = IPVERSION;  | 
    
    
    709  | 
     | 
     | 
    			ip->ip_hl = sizeof(struct ip) >> 2;  | 
    
    
    710  | 
     | 
     | 
    			ip->ip_tos = tos;  | 
    
    
    711  | 
     | 
     | 
    			ip->ip_id = 0;  | 
    
    
    712  | 
     | 
     | 
    			ip->ip_off = htons(df ? IP_DF : 0);  | 
    
    
    713  | 
     | 
     | 
    			ip->ip_ttl = ttl;  | 
    
    
    714  | 
     | 
     | 
    			ip->ip_p = IPPROTO_ICMP;  | 
    
    
    715  | 
     | 
     | 
    			if (source)  | 
    
    
    716  | 
     | 
     | 
    				ip->ip_src = from4.sin_addr;  | 
    
    
    717  | 
     | 
     | 
    			else  | 
    
    
    718  | 
     | 
     | 
    				ip->ip_src.s_addr = INADDR_ANY;  | 
    
    
    719  | 
     | 
     | 
    			ip->ip_dst = dst4.sin_addr;  | 
    
    
    720  | 
     | 
     | 
    		}  | 
    
    
    721  | 
     | 
     | 
     | 
    
    
    722  | 
     | 
     | 
    		/* record route option */  | 
    
    
    723  | 
     | 
     | 
    		if (options & F_RROUTE) { | 
    
    
    724  | 
     | 
     | 
    			if (IN_MULTICAST(ntohl(dst4.sin_addr.s_addr)))  | 
    
    
    725  | 
     | 
     | 
    				errx(1, "record route not valid to multicast"  | 
    
    
    726  | 
     | 
     | 
    				    " destinations");  | 
    
    
    727  | 
     | 
     | 
    			memset(rspace, 0, sizeof(rspace));  | 
    
    
    728  | 
     | 
     | 
    			rspace[IPOPT_OPTVAL] = IPOPT_RR;  | 
    
    
    729  | 
     | 
     | 
    			rspace[IPOPT_OLEN] = sizeof(rspace)-1;  | 
    
    
    730  | 
     | 
     | 
    			rspace[IPOPT_OFFSET] = IPOPT_MINOFF;  | 
    
    
    731  | 
     | 
     | 
    			if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,  | 
    
    
    732  | 
     | 
     | 
    			    sizeof(rspace)) < 0)  | 
    
    
    733  | 
     | 
     | 
    				err(1, "record route");  | 
    
    
    734  | 
     | 
     | 
    		}  | 
    
    
    735  | 
     | 
     | 
     | 
    
    
    736  | 
     | 
     | 
    		if ((moptions & MULTICAST_NOLOOP) &&  | 
    
    
    737  | 
     | 
     | 
    		    setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,  | 
    
    
    738  | 
     | 
     | 
    		    sizeof(loop)) < 0)  | 
    
    
    739  | 
     | 
     | 
    			err(1, "setsockopt IP_MULTICAST_LOOP");  | 
    
    
    740  | 
     | 
     | 
    		if ((moptions & MULTICAST_TTL) &&  | 
    
    
    741  | 
     | 
     | 
    		    setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,  | 
    
    
    742  | 
     | 
     | 
    		    sizeof(ttl)) < 0)  | 
    
    
    743  | 
     | 
     | 
    			err(1, "setsockopt IP_MULTICAST_TTL");  | 
    
    
    744  | 
     | 
     | 
    	}  | 
    
    
    745  | 
     | 
     | 
     | 
    
    
    746  | 
     | 
     | 
    	if (options & F_HOSTNAME) { | 
    
    
    747  | 
     | 
     | 
    		if (pledge("stdio inet dns flock rpath cpath wpath", NULL) == -1) | 
    
    
    748  | 
     | 
     | 
    			err(1, "pledge");  | 
    
    
    749  | 
     | 
     | 
    	} else { | 
    
    
    750  | 
     | 
     | 
    		if (pledge("stdio inet flock rpath cpath wpath", NULL) == -1) | 
    
    
    751  | 
     | 
     | 
    			err(1, "pledge");  | 
    
    
    752  | 
     | 
     | 
    	}  | 
    
    
    753  | 
     | 
     | 
     | 
    
    
    754  | 
     | 
     | 
    	arc4random_buf(&tv64_offset, sizeof(tv64_offset));  | 
    
    
    755  | 
     | 
     | 
    	arc4random_buf(&mac_key, sizeof(mac_key));  | 
    
    
    756  | 
     | 
     | 
     | 
    
    
    757  | 
     | 
     | 
    	printf("PING %s (", hostname); | 
    
    
    758  | 
     | 
     | 
    	if (options & F_VERBOSE)  | 
    
    
    759  | 
     | 
     | 
    		printf("%s --> ", pr_addr(from, from->sa_len)); | 
    
    
    760  | 
     | 
     | 
    	printf("%s): %d data bytes\n", pr_addr(dst, dst->sa_len), datalen); | 
    
    
    761  | 
     | 
     | 
     | 
    
    
    762  | 
     | 
     | 
    	smsghdr.msg_name = dst;  | 
    
    
    763  | 
     | 
     | 
    	smsghdr.msg_namelen = dst->sa_len;  | 
    
    
    764  | 
     | 
     | 
    	smsgiov.iov_base = (caddr_t)outpack;  | 
    
    
    765  | 
     | 
     | 
    	smsghdr.msg_iov = &smsgiov;  | 
    
    
    766  | 
     | 
     | 
    	smsghdr.msg_iovlen = 1;  | 
    
    
    767  | 
     | 
     | 
     | 
    
    
    768  | 
     | 
     | 
    	while (preload--)		/* Fire off them quickies. */  | 
    
    
    769  | 
     | 
     | 
    		pinger(s);  | 
    
    
    770  | 
     | 
     | 
     | 
    
    
    771  | 
     | 
     | 
    	(void)signal(SIGINT, onsignal);  | 
    
    
    772  | 
     | 
     | 
    	(void)signal(SIGINFO, onsignal);  | 
    
    
    773  | 
     | 
     | 
     | 
    
    
    774  | 
     | 
     | 
    	if (!(options & F_FLOOD)) { | 
    
    
    775  | 
     | 
     | 
    		(void)signal(SIGALRM, onsignal);  | 
    
    
    776  | 
     | 
     | 
    		itimer.it_interval = interval;  | 
    
    
    777  | 
     | 
     | 
    		itimer.it_value = interval;  | 
    
    
    778  | 
     | 
     | 
    		(void)setitimer(ITIMER_REAL, &itimer, NULL);  | 
    
    
    779  | 
     | 
     | 
    		if (ntransmitted == 0)  | 
    
    
    780  | 
     | 
     | 
    			retransmit(s);  | 
    
    
    781  | 
     | 
     | 
    	}  | 
    
    
    782  | 
     | 
     | 
     | 
    
    
    783  | 
     | 
     | 
    	seenalrm = seenint = 0;  | 
    
    
    784  | 
     | 
     | 
    	seeninfo = 0;  | 
    
    
    785  | 
     | 
     | 
     | 
    
    
    786  | 
     | 
     | 
    	for (;;) { | 
    
    
    787  | 
     | 
     | 
    		struct msghdr		m;  | 
    
    
    788  | 
     | 
     | 
    		union { | 
    
    
    789  | 
     | 
     | 
    			struct cmsghdr hdr;  | 
    
    
    790  | 
     | 
     | 
    			u_char buf[CMSG_SPACE(1024)];  | 
    
    
    791  | 
     | 
     | 
    		}			cmsgbuf;  | 
    
    
    792  | 
     | 
     | 
    		struct iovec		iov[1];  | 
    
    
    793  | 
     | 
     | 
    		struct pollfd		pfd;  | 
    
    
    794  | 
     | 
     | 
    		struct sockaddr_in	peer4;  | 
    
    
    795  | 
     | 
     | 
    		struct sockaddr_in6	peer6;  | 
    
    
    796  | 
     | 
     | 
    		ssize_t			cc;  | 
    
    
    797  | 
     | 
     | 
    		int			timeout;  | 
    
    
    798  | 
     | 
     | 
     | 
    
    
    799  | 
     | 
     | 
    		/* signal handling */  | 
    
    
    800  | 
     | 
     | 
    		if (seenint)  | 
    
    
    801  | 
     | 
     | 
    			break;  | 
    
    
    802  | 
     | 
     | 
    		if (seenalrm) { | 
    
    
    803  | 
     | 
     | 
    			retransmit(s);  | 
    
    
    804  | 
     | 
     | 
    			seenalrm = 0;  | 
    
    
    805  | 
     | 
     | 
    			if (ntransmitted - nreceived - 1 > nmissedmax) { | 
    
    
    806  | 
     | 
     | 
    				nmissedmax = ntransmitted - nreceived - 1;  | 
    
    
    807  | 
     | 
     | 
    				if (!(options & F_FLOOD) &&  | 
    
    
    808  | 
     | 
     | 
    				    (options & F_AUD_MISS))  | 
    
    
    809  | 
     | 
     | 
    					fputc('\a', stderr); | 
    
    
    810  | 
     | 
     | 
    			}  | 
    
    
    811  | 
     | 
     | 
    			continue;  | 
    
    
    812  | 
     | 
     | 
    		}  | 
    
    
    813  | 
     | 
     | 
    		if (seeninfo) { | 
    
    
    814  | 
     | 
     | 
    			summary();  | 
    
    
    815  | 
     | 
     | 
    			seeninfo = 0;  | 
    
    
    816  | 
     | 
     | 
    			continue;  | 
    
    
    817  | 
     | 
     | 
    		}  | 
    
    
    818  | 
     | 
     | 
     | 
    
    
    819  | 
     | 
     | 
    		if (options & F_FLOOD) { | 
    
    
    820  | 
     | 
     | 
    			(void)pinger(s);  | 
    
    
    821  | 
     | 
     | 
    			timeout = 10;  | 
    
    
    822  | 
     | 
     | 
    		} else  | 
    
    
    823  | 
     | 
     | 
    			timeout = INFTIM;  | 
    
    
    824  | 
     | 
     | 
     | 
    
    
    825  | 
     | 
     | 
    		pfd.fd = s;  | 
    
    
    826  | 
     | 
     | 
    		pfd.events = POLLIN;  | 
    
    
    827  | 
     | 
     | 
     | 
    
    
    828  | 
     | 
     | 
    		if (poll(&pfd, 1, timeout) <= 0)  | 
    
    
    829  | 
     | 
     | 
    			continue;  | 
    
    
    830  | 
     | 
     | 
     | 
    
    
    831  | 
     | 
     | 
    		if (v6flag) { | 
    
    
    832  | 
     | 
     | 
    			m.msg_name = &peer6;  | 
    
    
    833  | 
     | 
     | 
    			m.msg_namelen = sizeof(peer6);  | 
    
    
    834  | 
     | 
     | 
    		} else { | 
    
    
    835  | 
     | 
     | 
    			m.msg_name = &peer4;  | 
    
    
    836  | 
     | 
     | 
    			m.msg_namelen = sizeof(peer4);  | 
    
    
    837  | 
     | 
     | 
    		}  | 
    
    
    838  | 
     | 
     | 
    		memset(&iov, 0, sizeof(iov));  | 
    
    
    839  | 
     | 
     | 
    		iov[0].iov_base = (caddr_t)packet;  | 
    
    
    840  | 
     | 
     | 
    		iov[0].iov_len = packlen;  | 
    
    
    841  | 
     | 
     | 
    		m.msg_iov = iov;  | 
    
    
    842  | 
     | 
     | 
    		m.msg_iovlen = 1;  | 
    
    
    843  | 
     | 
     | 
    		m.msg_control = (caddr_t)&cmsgbuf.buf;  | 
    
    
    844  | 
     | 
     | 
    		m.msg_controllen = sizeof(cmsgbuf.buf);  | 
    
    
    845  | 
     | 
     | 
     | 
    
    
    846  | 
     | 
     | 
    		cc = recvmsg(s, &m, 0);  | 
    
    
    847  | 
     | 
     | 
    		if (cc < 0) { | 
    
    
    848  | 
     | 
     | 
    			if (errno != EINTR) { | 
    
    
    849  | 
     | 
     | 
    				warn("recvmsg"); | 
    
    
    850  | 
     | 
     | 
    				sleep(1);  | 
    
    
    851  | 
     | 
     | 
    			}  | 
    
    
    852  | 
     | 
     | 
    			continue;  | 
    
    
    853  | 
     | 
     | 
    		} else if (cc == 0) { | 
    
    
    854  | 
     | 
     | 
    			int mtu;  | 
    
    
    855  | 
     | 
     | 
     | 
    
    
    856  | 
     | 
     | 
    			/*  | 
    
    
    857  | 
     | 
     | 
    			 * receive control messages only. Process the  | 
    
    
    858  | 
     | 
     | 
    			 * exceptions (currently the only possibility is  | 
    
    
    859  | 
     | 
     | 
    			 * a path MTU notification.)  | 
    
    
    860  | 
     | 
     | 
    			 */  | 
    
    
    861  | 
     | 
     | 
    			if ((mtu = get_pathmtu(&m, &dst6)) > 0) { | 
    
    
    862  | 
     | 
     | 
    				if (options & F_VERBOSE) { | 
    
    
    863  | 
     | 
     | 
    					printf("new path MTU (%d) is " | 
    
    
    864  | 
     | 
     | 
    					    "notified\n", mtu);  | 
    
    
    865  | 
     | 
     | 
    				}  | 
    
    
    866  | 
     | 
     | 
    			}  | 
    
    
    867  | 
     | 
     | 
    			continue;  | 
    
    
    868  | 
     | 
     | 
    		} else  | 
    
    
    869  | 
     | 
     | 
    			pr_pack(packet, cc, &m);  | 
    
    
    870  | 
     | 
     | 
     | 
    
    
    871  | 
     | 
     | 
    		if (npackets && nreceived >= npackets)  | 
    
    
    872  | 
     | 
     | 
    			break;  | 
    
    
    873  | 
     | 
     | 
    	}  | 
    
    
    874  | 
     | 
     | 
    	summary();  | 
    
    
    875  | 
     | 
     | 
    	exit(nreceived == 0);  | 
    
    
    876  | 
     | 
     | 
    }  | 
    
    
    877  | 
     | 
     | 
     | 
    
    
    878  | 
     | 
     | 
    void  | 
    
    
    879  | 
     | 
     | 
    onsignal(int sig)  | 
    
    
    880  | 
     | 
     | 
    { | 
    
    
    881  | 
     | 
     | 
    	switch (sig) { | 
    
    
    882  | 
     | 
     | 
    	case SIGALRM:  | 
    
    
    883  | 
     | 
     | 
    		seenalrm++;  | 
    
    
    884  | 
     | 
     | 
    		break;  | 
    
    
    885  | 
     | 
     | 
    	case SIGINT:  | 
    
    
    886  | 
     | 
     | 
    		seenint++;  | 
    
    
    887  | 
     | 
     | 
    		break;  | 
    
    
    888  | 
     | 
     | 
    	case SIGINFO:  | 
    
    
    889  | 
     | 
     | 
    		seeninfo++;  | 
    
    
    890  | 
     | 
     | 
    		break;  | 
    
    
    891  | 
     | 
     | 
    	}  | 
    
    
    892  | 
     | 
     | 
    }  | 
    
    
    893  | 
     | 
     | 
     | 
    
    
    894  | 
     | 
     | 
    void  | 
    
    
    895  | 
     | 
     | 
    fill(char *bp, char *patp)  | 
    
    
    896  | 
     | 
     | 
    { | 
    
    
    897  | 
     | 
     | 
    	int ii, jj, kk;  | 
    
    
    898  | 
     | 
     | 
    	int pat[16];  | 
    
    
    899  | 
     | 
     | 
    	char *cp;  | 
    
    
    900  | 
     | 
     | 
     | 
    
    
    901  | 
     | 
     | 
    	for (cp = patp; *cp; cp++)  | 
    
    
    902  | 
     | 
     | 
    		if (!isxdigit((unsigned char)*cp))  | 
    
    
    903  | 
     | 
     | 
    			errx(1, "patterns must be specified as hex digits");  | 
    
    
    904  | 
     | 
     | 
    	ii = sscanf(patp,  | 
    
    
    905  | 
     | 
     | 
    	    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",  | 
    
    
    906  | 
     | 
     | 
    	    &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],  | 
    
    
    907  | 
     | 
     | 
    	    &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],  | 
    
    
    908  | 
     | 
     | 
    	    &pat[13], &pat[14], &pat[15]);  | 
    
    
    909  | 
     | 
     | 
     | 
    
    
    910  | 
     | 
     | 
    	if (ii > 0)  | 
    
    
    911  | 
     | 
     | 
    		for (kk = 0;  | 
    
    
    912  | 
     | 
     | 
    		    kk <= maxpayload - (ECHOLEN + ECHOTMLEN + ii);  | 
    
    
    913  | 
     | 
     | 
    		    kk += ii)  | 
    
    
    914  | 
     | 
     | 
    			for (jj = 0; jj < ii; ++jj)  | 
    
    
    915  | 
     | 
     | 
    				bp[jj + kk] = pat[jj];  | 
    
    
    916  | 
     | 
     | 
    	if (!(options & F_QUIET)) { | 
    
    
    917  | 
     | 
     | 
    		printf("PATTERN: 0x"); | 
    
    
    918  | 
     | 
     | 
    		for (jj = 0; jj < ii; ++jj)  | 
    
    
    919  | 
     | 
     | 
    			printf("%02x", bp[jj] & 0xFF); | 
    
    
    920  | 
     | 
     | 
    		printf("\n"); | 
    
    
    921  | 
     | 
     | 
    	}  | 
    
    
    922  | 
     | 
     | 
    }  | 
    
    
    923  | 
     | 
     | 
     | 
    
    
    924  | 
     | 
     | 
    void  | 
    
    
    925  | 
     | 
     | 
    summary(void)  | 
    
    
    926  | 
     | 
     | 
    { | 
    
    
    927  | 
     | 
     | 
    	printf("\n--- %s ping statistics ---\n", hostname); | 
    
    
    928  | 
     | 
     | 
    	printf("%lld packets transmitted, ", ntransmitted); | 
    
    
    929  | 
     | 
     | 
    	printf("%lld packets received, ", nreceived); | 
    
    
    930  | 
     | 
     | 
     | 
    
    
    931  | 
     | 
     | 
    	if (nrepeats)  | 
    
    
    932  | 
     | 
     | 
    		printf("%lld duplicates, ", nrepeats); | 
    
    
    933  | 
     | 
     | 
    	if (ntransmitted) { | 
    
    
    934  | 
     | 
     | 
    		if (nreceived > ntransmitted)  | 
    
    
    935  | 
     | 
     | 
    			printf("-- somebody's duplicating packets!"); | 
    
    
    936  | 
     | 
     | 
    		else  | 
    
    
    937  | 
     | 
     | 
    			printf("%.1f%% packet loss", | 
    
    
    938  | 
     | 
     | 
    			    ((((double)ntransmitted - nreceived) * 100) /  | 
    
    
    939  | 
     | 
     | 
    			    ntransmitted));  | 
    
    
    940  | 
     | 
     | 
    	}  | 
    
    
    941  | 
     | 
     | 
    	printf("\n"); | 
    
    
    942  | 
     | 
     | 
    	if (timinginfo) { | 
    
    
    943  | 
     | 
     | 
    		/* Only display average to microseconds */  | 
    
    
    944  | 
     | 
     | 
    		double num = nreceived + nrepeats;  | 
    
    
    945  | 
     | 
     | 
    		double avg = tsum / num;  | 
    
    
    946  | 
     | 
     | 
    		double dev = sqrt(fmax(0, tsumsq / num - avg * avg));  | 
    
    
    947  | 
     | 
     | 
    		printf("round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", | 
    
    
    948  | 
     | 
     | 
    		    tmin, avg, tmax, dev);  | 
    
    
    949  | 
     | 
     | 
    	}  | 
    
    
    950  | 
     | 
     | 
    }  | 
    
    
    951  | 
     | 
     | 
     | 
    
    
    952  | 
     | 
     | 
    /*  | 
    
    
    953  | 
     | 
     | 
     * pr_addr --  | 
    
    
    954  | 
     | 
     | 
     *	Return address in numeric form or a host name  | 
    
    
    955  | 
     | 
     | 
     */  | 
    
    
    956  | 
     | 
     | 
    const char *  | 
    
    
    957  | 
     | 
     | 
    pr_addr(struct sockaddr *addr, socklen_t addrlen)  | 
    
    
    958  | 
     | 
     | 
    { | 
    
    
    959  | 
     | 
     | 
    	static char buf[NI_MAXHOST];  | 
    
    
    960  | 
     | 
     | 
    	int flag = 0;  | 
    
    
    961  | 
     | 
     | 
     | 
    
    
    962  | 
     | 
     | 
    	if (!(options & F_HOSTNAME))  | 
    
    
    963  | 
     | 
     | 
    		flag |= NI_NUMERICHOST;  | 
    
    
    964  | 
     | 
     | 
     | 
    
    
    965  | 
     | 
     | 
    	if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)  | 
    
    
    966  | 
     | 
     | 
    		return (buf);  | 
    
    
    967  | 
     | 
     | 
    	else  | 
    
    
    968  | 
     | 
     | 
    		return "?";  | 
    
    
    969  | 
     | 
     | 
    }  | 
    
    
    970  | 
     | 
     | 
     | 
    
    
    971  | 
     | 
     | 
    /*  | 
    
    
    972  | 
     | 
     | 
     * retransmit --  | 
    
    
    973  | 
     | 
     | 
     *	This routine transmits another ping.  | 
    
    
    974  | 
     | 
     | 
     */  | 
    
    
    975  | 
     | 
     | 
    void  | 
    
    
    976  | 
     | 
     | 
    retransmit(int s)  | 
    
    
    977  | 
     | 
     | 
    { | 
    
    
    978  | 
     | 
     | 
    	struct itimerval itimer;  | 
    
    
    979  | 
     | 
     | 
    	static int last_time = 0;  | 
    
    
    980  | 
     | 
     | 
     | 
    
    
    981  | 
     | 
     | 
    	if (last_time) { | 
    
    
    982  | 
     | 
     | 
    		seenint = 1;	/* break out of ping event loop */  | 
    
    
    983  | 
     | 
     | 
    		return;  | 
    
    
    984  | 
     | 
     | 
    	}  | 
    
    
    985  | 
     | 
     | 
     | 
    
    
    986  | 
     | 
     | 
    	if (pinger(s) == 0)  | 
    
    
    987  | 
     | 
     | 
    		return;  | 
    
    
    988  | 
     | 
     | 
     | 
    
    
    989  | 
     | 
     | 
    	/*  | 
    
    
    990  | 
     | 
     | 
    	 * If we're not transmitting any more packets, change the timer  | 
    
    
    991  | 
     | 
     | 
    	 * to wait two round-trip times if we've received any packets or  | 
    
    
    992  | 
     | 
     | 
    	 * maxwait seconds if we haven't.  | 
    
    
    993  | 
     | 
     | 
    	 */  | 
    
    
    994  | 
     | 
     | 
    	if (nreceived) { | 
    
    
    995  | 
     | 
     | 
    		itimer.it_value.tv_sec = 2 * tmax / 1000;  | 
    
    
    996  | 
     | 
     | 
    		if (itimer.it_value.tv_sec == 0)  | 
    
    
    997  | 
     | 
     | 
    			itimer.it_value.tv_sec = 1;  | 
    
    
    998  | 
     | 
     | 
    	} else  | 
    
    
    999  | 
     | 
     | 
    		itimer.it_value.tv_sec = maxwait;  | 
    
    
    1000  | 
     | 
     | 
    	itimer.it_interval.tv_sec = 0;  | 
    
    
    1001  | 
     | 
     | 
    	itimer.it_interval.tv_usec = 0;  | 
    
    
    1002  | 
     | 
     | 
    	itimer.it_value.tv_usec = 0;  | 
    
    
    1003  | 
     | 
     | 
    	(void)setitimer(ITIMER_REAL, &itimer, NULL);  | 
    
    
    1004  | 
     | 
     | 
     | 
    
    
    1005  | 
     | 
     | 
    	/* When the alarm goes off we are done. */  | 
    
    
    1006  | 
     | 
     | 
    	last_time = 1;  | 
    
    
    1007  | 
     | 
     | 
    }  | 
    
    
    1008  | 
     | 
     | 
     | 
    
    
    1009  | 
     | 
     | 
    /*  | 
    
    
    1010  | 
     | 
     | 
     * pinger --  | 
    
    
    1011  | 
     | 
     | 
     *	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet  | 
    
    
    1012  | 
     | 
     | 
     * will be added on by the kernel.  The ID field is our UNIX process ID,  | 
    
    
    1013  | 
     | 
     | 
     * and the sequence number is an ascending integer.  The first 8 bytes  | 
    
    
    1014  | 
     | 
     | 
     * of the data portion are used to hold a UNIX "timeval" struct in VAX  | 
    
    
    1015  | 
     | 
     | 
     * byte-order, to compute the round-trip time.  | 
    
    
    1016  | 
     | 
     | 
     */  | 
    
    
    1017  | 
     | 
     | 
    int  | 
    
    
    1018  | 
     | 
     | 
    pinger(int s)  | 
    
    
    1019  | 
     | 
     | 
    { | 
    
    
    1020  | 
     | 
     | 
    	struct icmp *icp = NULL;  | 
    
    
    1021  | 
     | 
     | 
    	struct icmp6_hdr *icp6 = NULL;  | 
    
    
    1022  | 
     | 
     | 
    	int cc, i;  | 
    
    
    1023  | 
     | 
     | 
    	u_int16_t seq;  | 
    
    
    1024  | 
     | 
     | 
     | 
    
    
    1025  | 
     | 
     | 
    	if (npackets && ntransmitted >= npackets)  | 
    
    
    1026  | 
     | 
     | 
    		return(-1);	/* no more transmission */  | 
    
    
    1027  | 
     | 
     | 
     | 
    
    
    1028  | 
     | 
     | 
    	seq = htons(ntransmitted++);  | 
    
    
    1029  | 
     | 
     | 
     | 
    
    
    1030  | 
     | 
     | 
    	if (v6flag) { | 
    
    
    1031  | 
     | 
     | 
    		icp6 = (struct icmp6_hdr *)outpack;  | 
    
    
    1032  | 
     | 
     | 
    		memset(icp6, 0, sizeof(*icp6));  | 
    
    
    1033  | 
     | 
     | 
    		icp6->icmp6_cksum = 0;  | 
    
    
    1034  | 
     | 
     | 
    		icp6->icmp6_type = ICMP6_ECHO_REQUEST;  | 
    
    
    1035  | 
     | 
     | 
    		icp6->icmp6_code = 0;  | 
    
    
    1036  | 
     | 
     | 
    		icp6->icmp6_id = htons(ident);  | 
    
    
    1037  | 
     | 
     | 
    		icp6->icmp6_seq = seq;  | 
    
    
    1038  | 
     | 
     | 
    	} else { | 
    
    
    1039  | 
     | 
     | 
    		icp = (struct icmp *)outpack;  | 
    
    
    1040  | 
     | 
     | 
    		icp->icmp_type = ICMP_ECHO;  | 
    
    
    1041  | 
     | 
     | 
    		icp->icmp_code = 0;  | 
    
    
    1042  | 
     | 
     | 
    		icp->icmp_cksum = 0;  | 
    
    
    1043  | 
     | 
     | 
    		icp->icmp_seq = seq;  | 
    
    
    1044  | 
     | 
     | 
    		icp->icmp_id = ident;			/* ID */  | 
    
    
    1045  | 
     | 
     | 
    	}  | 
    
    
    1046  | 
     | 
     | 
    	CLR(ntohs(seq) % mx_dup_ck);  | 
    
    
    1047  | 
     | 
     | 
     | 
    
    
    1048  | 
     | 
     | 
    	if (timing) { | 
    
    
    1049  | 
     | 
     | 
    		SIPHASH_CTX ctx;  | 
    
    
    1050  | 
     | 
     | 
    		struct timespec ts;  | 
    
    
    1051  | 
     | 
     | 
    		struct payload payload;  | 
    
    
    1052  | 
     | 
     | 
    		struct tv64 *tv64 = &payload.tv64;  | 
    
    
    1053  | 
     | 
     | 
     | 
    
    
    1054  | 
     | 
     | 
    		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)  | 
    
    
    1055  | 
     | 
     | 
    			err(1, "clock_gettime(CLOCK_MONOTONIC)");  | 
    
    
    1056  | 
     | 
     | 
    		tv64->tv64_sec = htobe64((u_int64_t)ts.tv_sec +  | 
    
    
    1057  | 
     | 
     | 
    		    tv64_offset.tv64_sec);  | 
    
    
    1058  | 
     | 
     | 
    		tv64->tv64_nsec = htobe64((u_int64_t)ts.tv_nsec +  | 
    
    
    1059  | 
     | 
     | 
    		    tv64_offset.tv64_nsec);  | 
    
    
    1060  | 
     | 
     | 
     | 
    
    
    1061  | 
     | 
     | 
    		SipHash24_Init(&ctx, &mac_key);  | 
    
    
    1062  | 
     | 
     | 
    		SipHash24_Update(&ctx, tv64, sizeof(*tv64));  | 
    
    
    1063  | 
     | 
     | 
    		SipHash24_Update(&ctx, &ident, sizeof(ident));  | 
    
    
    1064  | 
     | 
     | 
    		SipHash24_Update(&ctx, &seq, sizeof(seq));  | 
    
    
    1065  | 
     | 
     | 
    		SipHash24_Final(&payload.mac, &ctx);  | 
    
    
    1066  | 
     | 
     | 
     | 
    
    
    1067  | 
     | 
     | 
    		memcpy(&outpack[ECHOLEN], &payload, sizeof(payload));  | 
    
    
    1068  | 
     | 
     | 
    	}  | 
    
    
    1069  | 
     | 
     | 
     | 
    
    
    1070  | 
     | 
     | 
    	cc = ECHOLEN + datalen;  | 
    
    
    1071  | 
     | 
     | 
     | 
    
    
    1072  | 
     | 
     | 
    	if (!v6flag) { | 
    
    
    1073  | 
     | 
     | 
    		/* compute ICMP checksum here */  | 
    
    
    1074  | 
     | 
     | 
    		icp->icmp_cksum = in_cksum((u_short *)icp, cc);  | 
    
    
    1075  | 
     | 
     | 
     | 
    
    
    1076  | 
     | 
     | 
    		if (options & F_HDRINCL) { | 
    
    
    1077  | 
     | 
     | 
    			struct ip *ip = (struct ip *)outpackhdr;  | 
    
    
    1078  | 
     | 
     | 
     | 
    
    
    1079  | 
     | 
     | 
    			smsgiov.iov_base = (caddr_t)outpackhdr;  | 
    
    
    1080  | 
     | 
     | 
    			cc += sizeof(struct ip);  | 
    
    
    1081  | 
     | 
     | 
    			ip->ip_len = htons(cc);  | 
    
    
    1082  | 
     | 
     | 
    			ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);  | 
    
    
    1083  | 
     | 
     | 
    		}  | 
    
    
    1084  | 
     | 
     | 
    	}  | 
    
    
    1085  | 
     | 
     | 
     | 
    
    
    1086  | 
     | 
     | 
    	smsgiov.iov_len = cc;  | 
    
    
    1087  | 
     | 
     | 
     | 
    
    
    1088  | 
     | 
     | 
    	i = sendmsg(s, &smsghdr, 0);  | 
    
    
    1089  | 
     | 
     | 
     | 
    
    
    1090  | 
     | 
     | 
    	if (i < 0 || i != cc) { | 
    
    
    1091  | 
     | 
     | 
    		if (i < 0)  | 
    
    
    1092  | 
     | 
     | 
    			warn("sendmsg"); | 
    
    
    1093  | 
     | 
     | 
    		printf("ping: wrote %s %d chars, ret=%d\n", hostname, cc, i); | 
    
    
    1094  | 
     | 
     | 
    	}  | 
    
    
    1095  | 
     | 
     | 
    	if (!(options & F_QUIET) && (options & F_FLOOD))  | 
    
    
    1096  | 
     | 
     | 
    		write(STDOUT_FILENO, &DOT, 1);  | 
    
    
    1097  | 
     | 
     | 
     | 
    
    
    1098  | 
     | 
     | 
    	return (0);  | 
    
    
    1099  | 
     | 
     | 
    }  | 
    
    
    1100  | 
     | 
     | 
     | 
    
    
    1101  | 
     | 
     | 
    /*  | 
    
    
    1102  | 
     | 
     | 
     * pr_pack --  | 
    
    
    1103  | 
     | 
     | 
     *	Print out the packet, if it came from us.  This logic is necessary  | 
    
    
    1104  | 
     | 
     | 
     * because ALL readers of the ICMP socket get a copy of ALL ICMP packets  | 
    
    
    1105  | 
     | 
     | 
     * which arrive ('tis only fair).  This permits multiple copies of this | 
    
    
    1106  | 
     | 
     | 
     * program to be run without having intermingled output (or statistics!).  | 
    
    
    1107  | 
     | 
     | 
     */  | 
    
    
    1108  | 
     | 
     | 
    void  | 
    
    
    1109  | 
     | 
     | 
    pr_pack(u_char *buf, int cc, struct msghdr *mhdr)  | 
    
    
    1110  | 
     | 
     | 
    { | 
    
    
    1111  | 
     | 
     | 
    	struct ip *ip = NULL;  | 
    
    
    1112  | 
     | 
     | 
    	struct icmp *icp = NULL;  | 
    
    
    1113  | 
     | 
     | 
    	struct icmp6_hdr *icp6 = NULL;  | 
    
    
    1114  | 
     | 
     | 
    	struct timespec ts, tp;  | 
    
    
    1115  | 
     | 
     | 
    	struct payload payload;  | 
    
    
    1116  | 
     | 
     | 
    	struct sockaddr *from;  | 
    
    
    1117  | 
     | 
     | 
    	socklen_t fromlen;  | 
    
    
    1118  | 
     | 
     | 
    	double triptime = 0;  | 
    
    
    1119  | 
     | 
     | 
    	int i, dupflag;  | 
    
    
    1120  | 
     | 
     | 
    	int hlen = -1, hoplim = -1, echo_reply = 0;  | 
    
    
    1121  | 
     | 
     | 
    	u_int16_t seq;  | 
    
    
    1122  | 
     | 
     | 
    	u_char *cp, *dp;  | 
    
    
    1123  | 
     | 
     | 
    	char* pkttime;  | 
    
    
    1124  | 
     | 
     | 
     | 
    
    
    1125  | 
     | 
     | 
    	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)  | 
    
    
    1126  | 
     | 
     | 
    		err(1, "clock_gettime(CLOCK_MONOTONIC)");  | 
    
    
    1127  | 
     | 
     | 
     | 
    
    
    1128  | 
     | 
     | 
    	if (v6flag) { | 
    
    
    1129  | 
     | 
     | 
    		if (!mhdr || !mhdr->msg_name ||  | 
    
    
    1130  | 
     | 
     | 
    		    mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||  | 
    
    
    1131  | 
     | 
     | 
    		    ((struct sockaddr *)mhdr->msg_name)->sa_family !=  | 
    
    
    1132  | 
     | 
     | 
    		    AF_INET6) { | 
    
    
    1133  | 
     | 
     | 
    			if (options & F_VERBOSE)  | 
    
    
    1134  | 
     | 
     | 
    				warnx("invalid peername"); | 
    
    
    1135  | 
     | 
     | 
    			return;  | 
    
    
    1136  | 
     | 
     | 
    		}  | 
    
    
    1137  | 
     | 
     | 
    		from = (struct sockaddr *)mhdr->msg_name;  | 
    
    
    1138  | 
     | 
     | 
    		fromlen = mhdr->msg_namelen;  | 
    
    
    1139  | 
     | 
     | 
     | 
    
    
    1140  | 
     | 
     | 
    		if (cc < sizeof(struct icmp6_hdr)) { | 
    
    
    1141  | 
     | 
     | 
    			if (options & F_VERBOSE)  | 
    
    
    1142  | 
     | 
     | 
    				warnx("packet too short (%d bytes) from %s", cc, | 
    
    
    1143  | 
     | 
     | 
    				    pr_addr(from, fromlen));  | 
    
    
    1144  | 
     | 
     | 
    			return;  | 
    
    
    1145  | 
     | 
     | 
    		}  | 
    
    
    1146  | 
     | 
     | 
    		icp6 = (struct icmp6_hdr *)buf;  | 
    
    
    1147  | 
     | 
     | 
     | 
    
    
    1148  | 
     | 
     | 
    		if ((hoplim = get_hoplim(mhdr)) == -1) { | 
    
    
    1149  | 
     | 
     | 
    			warnx("failed to get receiving hop limit"); | 
    
    
    1150  | 
     | 
     | 
    			return;  | 
    
    
    1151  | 
     | 
     | 
    		}  | 
    
    
    1152  | 
     | 
     | 
     | 
    
    
    1153  | 
     | 
     | 
    		if (icp6->icmp6_type == ICMP6_ECHO_REPLY) { | 
    
    
    1154  | 
     | 
     | 
    			if (ntohs(icp6->icmp6_id) != ident)  | 
    
    
    1155  | 
     | 
     | 
    				return;			/* 'Twas not our ECHO */  | 
    
    
    1156  | 
     | 
     | 
    			seq = icp6->icmp6_seq;  | 
    
    
    1157  | 
     | 
     | 
    			echo_reply = 1;  | 
    
    
    1158  | 
     | 
     | 
    			pkttime = (char *)(icp6 + 1);  | 
    
    
    1159  | 
     | 
     | 
    		}  | 
    
    
    1160  | 
     | 
     | 
    	} else { | 
    
    
    1161  | 
     | 
     | 
    		if (!mhdr || !mhdr->msg_name ||  | 
    
    
    1162  | 
     | 
     | 
    		    mhdr->msg_namelen != sizeof(struct sockaddr_in) ||  | 
    
    
    1163  | 
     | 
     | 
    		    ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET) { | 
    
    
    1164  | 
     | 
     | 
    			if (options & F_VERBOSE)  | 
    
    
    1165  | 
     | 
     | 
    				warnx("invalid peername"); | 
    
    
    1166  | 
     | 
     | 
    			return;  | 
    
    
    1167  | 
     | 
     | 
    		}  | 
    
    
    1168  | 
     | 
     | 
     | 
    
    
    1169  | 
     | 
     | 
    		from = (struct sockaddr *)mhdr->msg_name;  | 
    
    
    1170  | 
     | 
     | 
    		fromlen = mhdr->msg_namelen;  | 
    
    
    1171  | 
     | 
     | 
     | 
    
    
    1172  | 
     | 
     | 
    		/* Check the IP header */  | 
    
    
    1173  | 
     | 
     | 
    		ip = (struct ip *)buf;  | 
    
    
    1174  | 
     | 
     | 
    		hlen = ip->ip_hl << 2;  | 
    
    
    1175  | 
     | 
     | 
    		if (cc < hlen + ICMP_MINLEN) { | 
    
    
    1176  | 
     | 
     | 
    			if (options & F_VERBOSE)  | 
    
    
    1177  | 
     | 
     | 
    				warnx("packet too short (%d bytes) from %s", cc, | 
    
    
    1178  | 
     | 
     | 
    				    pr_addr(from, fromlen));  | 
    
    
    1179  | 
     | 
     | 
    			return;  | 
    
    
    1180  | 
     | 
     | 
    		}  | 
    
    
    1181  | 
     | 
     | 
     | 
    
    
    1182  | 
     | 
     | 
    		/* Now the ICMP part */  | 
    
    
    1183  | 
     | 
     | 
    		cc -= hlen;  | 
    
    
    1184  | 
     | 
     | 
    		icp = (struct icmp *)(buf + hlen);  | 
    
    
    1185  | 
     | 
     | 
    		if (icp->icmp_type == ICMP_ECHOREPLY) { | 
    
    
    1186  | 
     | 
     | 
    			if (icp->icmp_id != ident)  | 
    
    
    1187  | 
     | 
     | 
    				return;			/* 'Twas not our ECHO */  | 
    
    
    1188  | 
     | 
     | 
    			seq = icp->icmp_seq;  | 
    
    
    1189  | 
     | 
     | 
    			echo_reply = 1;  | 
    
    
    1190  | 
     | 
     | 
    			pkttime = (char *)icp->icmp_data;  | 
    
    
    1191  | 
     | 
     | 
    		}  | 
    
    
    1192  | 
     | 
     | 
    	}  | 
    
    
    1193  | 
     | 
     | 
     | 
    
    
    1194  | 
     | 
     | 
    	if (echo_reply) { | 
    
    
    1195  | 
     | 
     | 
    		++nreceived;  | 
    
    
    1196  | 
     | 
     | 
    		if (cc >= ECHOLEN + ECHOTMLEN) { | 
    
    
    1197  | 
     | 
     | 
    			SIPHASH_CTX ctx;  | 
    
    
    1198  | 
     | 
     | 
    			struct tv64 *tv64;  | 
    
    
    1199  | 
     | 
     | 
    			u_int8_t mac[SIPHASH_DIGEST_LENGTH];  | 
    
    
    1200  | 
     | 
     | 
     | 
    
    
    1201  | 
     | 
     | 
    			memcpy(&payload, pkttime, sizeof(payload));  | 
    
    
    1202  | 
     | 
     | 
    			tv64 = &payload.tv64;  | 
    
    
    1203  | 
     | 
     | 
     | 
    
    
    1204  | 
     | 
     | 
    			SipHash24_Init(&ctx, &mac_key);  | 
    
    
    1205  | 
     | 
     | 
    			SipHash24_Update(&ctx, tv64, sizeof(*tv64));  | 
    
    
    1206  | 
     | 
     | 
    			SipHash24_Update(&ctx, &ident, sizeof(ident));  | 
    
    
    1207  | 
     | 
     | 
    			SipHash24_Update(&ctx, &seq, sizeof(seq));  | 
    
    
    1208  | 
     | 
     | 
    			SipHash24_Final(mac, &ctx);  | 
    
    
    1209  | 
     | 
     | 
     | 
    
    
    1210  | 
     | 
     | 
    			if (timingsafe_memcmp(mac, &payload.mac,  | 
    
    
    1211  | 
     | 
     | 
    			    sizeof(mac)) != 0) { | 
    
    
    1212  | 
     | 
     | 
    				printf("signature mismatch!\n"); | 
    
    
    1213  | 
     | 
     | 
    				return;  | 
    
    
    1214  | 
     | 
     | 
    			}  | 
    
    
    1215  | 
     | 
     | 
    			timinginfo=1;  | 
    
    
    1216  | 
     | 
     | 
     | 
    
    
    1217  | 
     | 
     | 
    			tp.tv_sec = betoh64(tv64->tv64_sec) -  | 
    
    
    1218  | 
     | 
     | 
    			    tv64_offset.tv64_sec;  | 
    
    
    1219  | 
     | 
     | 
    			tp.tv_nsec = betoh64(tv64->tv64_nsec) -  | 
    
    
    1220  | 
     | 
     | 
    			    tv64_offset.tv64_nsec;  | 
    
    
    1221  | 
     | 
     | 
     | 
    
    
    1222  | 
     | 
     | 
    			timespecsub(&ts, &tp, &ts);  | 
    
    
    1223  | 
     | 
     | 
    			triptime = ((double)ts.tv_sec) * 1000.0 +  | 
    
    
    1224  | 
     | 
     | 
    			    ((double)ts.tv_nsec) / 1000000.0;  | 
    
    
    1225  | 
     | 
     | 
    			tsum += triptime;  | 
    
    
    1226  | 
     | 
     | 
    			tsumsq += triptime * triptime;  | 
    
    
    1227  | 
     | 
     | 
    			if (triptime < tmin)  | 
    
    
    1228  | 
     | 
     | 
    				tmin = triptime;  | 
    
    
    1229  | 
     | 
     | 
    			if (triptime > tmax)  | 
    
    
    1230  | 
     | 
     | 
    				tmax = triptime;  | 
    
    
    1231  | 
     | 
     | 
    		}  | 
    
    
    1232  | 
     | 
     | 
     | 
    
    
    1233  | 
     | 
     | 
    		if (TST(ntohs(seq) % mx_dup_ck)) { | 
    
    
    1234  | 
     | 
     | 
    			++nrepeats;  | 
    
    
    1235  | 
     | 
     | 
    			--nreceived;  | 
    
    
    1236  | 
     | 
     | 
    			dupflag = 1;  | 
    
    
    1237  | 
     | 
     | 
    		} else { | 
    
    
    1238  | 
     | 
     | 
    			SET(ntohs(seq) % mx_dup_ck);  | 
    
    
    1239  | 
     | 
     | 
    			dupflag = 0;  | 
    
    
    1240  | 
     | 
     | 
    		}  | 
    
    
    1241  | 
     | 
     | 
     | 
    
    
    1242  | 
     | 
     | 
    		if (options & F_QUIET)  | 
    
    
    1243  | 
     | 
     | 
    			return;  | 
    
    
    1244  | 
     | 
     | 
     | 
    
    
    1245  | 
     | 
     | 
    		if (options & F_FLOOD)  | 
    
    
    1246  | 
     | 
     | 
    			write(STDOUT_FILENO, &BSPACE, 1);  | 
    
    
    1247  | 
     | 
     | 
    		else { | 
    
    
    1248  | 
     | 
     | 
    			printf("%d bytes from %s: icmp_seq=%u", cc, | 
    
    
    1249  | 
     | 
     | 
    			    pr_addr(from, fromlen), ntohs(seq));  | 
    
    
    1250  | 
     | 
     | 
    			if (v6flag)  | 
    
    
    1251  | 
     | 
     | 
    				printf(" hlim=%d", hoplim); | 
    
    
    1252  | 
     | 
     | 
    			else  | 
    
    
    1253  | 
     | 
     | 
    				printf(" ttl=%d", ip->ip_ttl); | 
    
    
    1254  | 
     | 
     | 
    			if (cc >= ECHOLEN + ECHOTMLEN)  | 
    
    
    1255  | 
     | 
     | 
    				printf(" time=%.3f ms", triptime); | 
    
    
    1256  | 
     | 
     | 
    			if (dupflag)  | 
    
    
    1257  | 
     | 
     | 
    				printf(" (DUP!)"); | 
    
    
    1258  | 
     | 
     | 
    			/* check the data */  | 
    
    
    1259  | 
     | 
     | 
    			if (cc - ECHOLEN < datalen)  | 
    
    
    1260  | 
     | 
     | 
    				printf(" (TRUNC!)"); | 
    
    
    1261  | 
     | 
     | 
    			if (v6flag)  | 
    
    
    1262  | 
     | 
     | 
    				cp = buf + ECHOLEN + ECHOTMLEN;  | 
    
    
    1263  | 
     | 
     | 
    			else  | 
    
    
    1264  | 
     | 
     | 
    				cp = (u_char *)&icp->icmp_data[ECHOTMLEN];  | 
    
    
    1265  | 
     | 
     | 
    			dp = &outpack[ECHOLEN + ECHOTMLEN];  | 
    
    
    1266  | 
     | 
     | 
    			for (i = ECHOLEN + ECHOTMLEN;  | 
    
    
    1267  | 
     | 
     | 
    			    i < cc && i < datalen;  | 
    
    
    1268  | 
     | 
     | 
    			    ++i, ++cp, ++dp) { | 
    
    
    1269  | 
     | 
     | 
    				if (*cp != *dp) { | 
    
    
    1270  | 
     | 
     | 
    					printf("\nwrong data byte #%d " | 
    
    
    1271  | 
     | 
     | 
    					    "should be 0x%x but was 0x%x",  | 
    
    
    1272  | 
     | 
     | 
    					    i - ECHOLEN, *dp, *cp);  | 
    
    
    1273  | 
     | 
     | 
    					if (v6flag)  | 
    
    
    1274  | 
     | 
     | 
    						cp = buf + ECHOLEN;  | 
    
    
    1275  | 
     | 
     | 
    					else  | 
    
    
    1276  | 
     | 
     | 
    						cp = (u_char *)  | 
    
    
    1277  | 
     | 
     | 
    						    &icp->icmp_data[0];  | 
    
    
    1278  | 
     | 
     | 
    					for (i = ECHOLEN; i < cc && i < datalen;  | 
    
    
    1279  | 
     | 
     | 
    					    ++i, ++cp) { | 
    
    
    1280  | 
     | 
     | 
    						if ((i % 32) == 8)  | 
    
    
    1281  | 
     | 
     | 
    							printf("\n\t"); | 
    
    
    1282  | 
     | 
     | 
    						printf("%x ", *cp); | 
    
    
    1283  | 
     | 
     | 
    					}  | 
    
    
    1284  | 
     | 
     | 
    					break;  | 
    
    
    1285  | 
     | 
     | 
    				}  | 
    
    
    1286  | 
     | 
     | 
    			}  | 
    
    
    1287  | 
     | 
     | 
    		}  | 
    
    
    1288  | 
     | 
     | 
    	} else { | 
    
    
    1289  | 
     | 
     | 
    		/* We've got something other than an ECHOREPLY */  | 
    
    
    1290  | 
     | 
     | 
    		if (!(options & F_VERBOSE))  | 
    
    
    1291  | 
     | 
     | 
    			return;  | 
    
    
    1292  | 
     | 
     | 
    		printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); | 
    
    
    1293  | 
     | 
     | 
    		if (v6flag)  | 
    
    
    1294  | 
     | 
     | 
    			pr_icmph6(icp6, buf + cc);  | 
    
    
    1295  | 
     | 
     | 
    		else  | 
    
    
    1296  | 
     | 
     | 
    			pr_icmph(icp);  | 
    
    
    1297  | 
     | 
     | 
    	}  | 
    
    
    1298  | 
     | 
     | 
     | 
    
    
    1299  | 
     | 
     | 
    	/* Display any IP options */  | 
    
    
    1300  | 
     | 
     | 
    	if (!v6flag && hlen > sizeof(struct ip))  | 
    
    
    1301  | 
     | 
     | 
    		pr_ipopt(hlen, buf);  | 
    
    
    1302  | 
     | 
     | 
     | 
    
    
    1303  | 
     | 
     | 
    	if (!(options & F_FLOOD)) { | 
    
    
    1304  | 
     | 
     | 
    		putchar('\n'); | 
    
    
    1305  | 
     | 
     | 
    		if (v6flag && (options & F_VERBOSE))  | 
    
    
    1306  | 
     | 
     | 
    			pr_exthdrs(mhdr);  | 
    
    
    1307  | 
     | 
     | 
    		fflush(stdout);  | 
    
    
    1308  | 
     | 
     | 
    		if (options & F_AUD_RECV)  | 
    
    
    1309  | 
     | 
     | 
    			fputc('\a', stderr); | 
    
    
    1310  | 
     | 
     | 
    	}  | 
    
    
    1311  | 
     | 
     | 
    }  | 
    
    
    1312  | 
     | 
     | 
     | 
    
    
    1313  | 
     | 
     | 
    void  | 
    
    
    1314  | 
     | 
     | 
    pr_ipopt(int hlen, u_char *buf)  | 
    
    
    1315  | 
     | 
     | 
    { | 
    
    
    1316  | 
     | 
     | 
    	static int old_rrlen;  | 
    
    
    1317  | 
     | 
     | 
    	static char old_rr[MAX_IPOPTLEN];  | 
    
    
    1318  | 
     | 
     | 
    	struct sockaddr_in s_in;  | 
    
    
    1319  | 
     | 
     | 
    	in_addr_t l;  | 
    
    
    1320  | 
     | 
     | 
    	u_int i, j;  | 
    
    
    1321  | 
     | 
     | 
    	u_char *cp;  | 
    
    
    1322  | 
     | 
     | 
     | 
    
    
    1323  | 
     | 
     | 
    	cp = buf + sizeof(struct ip);  | 
    
    
    1324  | 
     | 
     | 
     | 
    
    
    1325  | 
     | 
     | 
    	s_in.sin_len = sizeof(s_in);  | 
    
    
    1326  | 
     | 
     | 
    	s_in.sin_family = AF_INET;  | 
    
    
    1327  | 
     | 
     | 
     | 
    
    
    1328  | 
     | 
     | 
    	for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) { | 
    
    
    1329  | 
     | 
     | 
    		switch (*cp) { | 
    
    
    1330  | 
     | 
     | 
    		case IPOPT_EOL:  | 
    
    
    1331  | 
     | 
     | 
    			hlen = 0;  | 
    
    
    1332  | 
     | 
     | 
    			break;  | 
    
    
    1333  | 
     | 
     | 
    		case IPOPT_LSRR:  | 
    
    
    1334  | 
     | 
     | 
    			printf("\nLSRR: "); | 
    
    
    1335  | 
     | 
     | 
    			hlen -= 2;  | 
    
    
    1336  | 
     | 
     | 
    			j = *++cp;  | 
    
    
    1337  | 
     | 
     | 
    			++cp;  | 
    
    
    1338  | 
     | 
     | 
    			i = 0;  | 
    
    
    1339  | 
     | 
     | 
    			if (j > IPOPT_MINOFF) { | 
    
    
    1340  | 
     | 
     | 
    				for (;;) { | 
    
    
    1341  | 
     | 
     | 
    					l = *++cp;  | 
    
    
    1342  | 
     | 
     | 
    					l = (l<<8) + *++cp;  | 
    
    
    1343  | 
     | 
     | 
    					l = (l<<8) + *++cp;  | 
    
    
    1344  | 
     | 
     | 
    					l = (l<<8) + *++cp;  | 
    
    
    1345  | 
     | 
     | 
    					if (l == 0)  | 
    
    
    1346  | 
     | 
     | 
    						printf("\t0.0.0.0"); | 
    
    
    1347  | 
     | 
     | 
    					else { | 
    
    
    1348  | 
     | 
     | 
    						s_in.sin_addr.s_addr = ntohl(l);  | 
    
    
    1349  | 
     | 
     | 
    						printf("\t%s", | 
    
    
    1350  | 
     | 
     | 
    						    pr_addr((struct sockaddr*)  | 
    
    
    1351  | 
     | 
     | 
    						    &s_in, sizeof(s_in)));  | 
    
    
    1352  | 
     | 
     | 
    					}  | 
    
    
    1353  | 
     | 
     | 
    					hlen -= 4;  | 
    
    
    1354  | 
     | 
     | 
    					j -= 4;  | 
    
    
    1355  | 
     | 
     | 
    					i += 4;  | 
    
    
    1356  | 
     | 
     | 
    					if (j <= IPOPT_MINOFF)  | 
    
    
    1357  | 
     | 
     | 
    						break;  | 
    
    
    1358  | 
     | 
     | 
    					if (i >= MAX_IPOPTLEN) { | 
    
    
    1359  | 
     | 
     | 
    						printf("\t(truncated route)"); | 
    
    
    1360  | 
     | 
     | 
    						break;  | 
    
    
    1361  | 
     | 
     | 
    					}  | 
    
    
    1362  | 
     | 
     | 
    					putchar('\n'); | 
    
    
    1363  | 
     | 
     | 
    				}  | 
    
    
    1364  | 
     | 
     | 
    			}  | 
    
    
    1365  | 
     | 
     | 
    			break;  | 
    
    
    1366  | 
     | 
     | 
    		case IPOPT_RR:  | 
    
    
    1367  | 
     | 
     | 
    			j = *++cp;		/* get length */  | 
    
    
    1368  | 
     | 
     | 
    			i = *++cp;		/* and pointer */  | 
    
    
    1369  | 
     | 
     | 
    			hlen -= 2;  | 
    
    
    1370  | 
     | 
     | 
    			if (i > j)  | 
    
    
    1371  | 
     | 
     | 
    				i = j;  | 
    
    
    1372  | 
     | 
     | 
    			i -= IPOPT_MINOFF;  | 
    
    
    1373  | 
     | 
     | 
    			if (i <= 0)  | 
    
    
    1374  | 
     | 
     | 
    				continue;  | 
    
    
    1375  | 
     | 
     | 
    			if (i == old_rrlen &&  | 
    
    
    1376  | 
     | 
     | 
    			    cp == buf + sizeof(struct ip) + 2 &&  | 
    
    
    1377  | 
     | 
     | 
    			    !memcmp(cp, old_rr, i) &&  | 
    
    
    1378  | 
     | 
     | 
    			    !(options & F_FLOOD)) { | 
    
    
    1379  | 
     | 
     | 
    				printf("\t(same route)"); | 
    
    
    1380  | 
     | 
     | 
    				i = (i + 3) & ~0x3;  | 
    
    
    1381  | 
     | 
     | 
    				hlen -= i;  | 
    
    
    1382  | 
     | 
     | 
    				cp += i;  | 
    
    
    1383  | 
     | 
     | 
    				break;  | 
    
    
    1384  | 
     | 
     | 
    			}  | 
    
    
    1385  | 
     | 
     | 
    			if (i < MAX_IPOPTLEN) { | 
    
    
    1386  | 
     | 
     | 
    				old_rrlen = i;  | 
    
    
    1387  | 
     | 
     | 
    				memcpy(old_rr, cp, i);  | 
    
    
    1388  | 
     | 
     | 
    			} else  | 
    
    
    1389  | 
     | 
     | 
    				old_rrlen = 0;  | 
    
    
    1390  | 
     | 
     | 
     | 
    
    
    1391  | 
     | 
     | 
    			printf("\nRR: "); | 
    
    
    1392  | 
     | 
     | 
    			j = 0;  | 
    
    
    1393  | 
     | 
     | 
    			for (;;) { | 
    
    
    1394  | 
     | 
     | 
    				l = *++cp;  | 
    
    
    1395  | 
     | 
     | 
    				l = (l<<8) + *++cp;  | 
    
    
    1396  | 
     | 
     | 
    				l = (l<<8) + *++cp;  | 
    
    
    1397  | 
     | 
     | 
    				l = (l<<8) + *++cp;  | 
    
    
    1398  | 
     | 
     | 
    				if (l == 0)  | 
    
    
    1399  | 
     | 
     | 
    					printf("\t0.0.0.0"); | 
    
    
    1400  | 
     | 
     | 
    				else { | 
    
    
    1401  | 
     | 
     | 
    					s_in.sin_addr.s_addr = ntohl(l);  | 
    
    
    1402  | 
     | 
     | 
    					printf("\t%s", | 
    
    
    1403  | 
     | 
     | 
    					    pr_addr((struct sockaddr*)&s_in,  | 
    
    
    1404  | 
     | 
     | 
    					    sizeof(s_in)));  | 
    
    
    1405  | 
     | 
     | 
    				}  | 
    
    
    1406  | 
     | 
     | 
    				hlen -= 4;  | 
    
    
    1407  | 
     | 
     | 
    				i -= 4;  | 
    
    
    1408  | 
     | 
     | 
    				j += 4;  | 
    
    
    1409  | 
     | 
     | 
    				if (i <= 0)  | 
    
    
    1410  | 
     | 
     | 
    					break;  | 
    
    
    1411  | 
     | 
     | 
    				if (j >= MAX_IPOPTLEN) { | 
    
    
    1412  | 
     | 
     | 
    					printf("\t(truncated route)"); | 
    
    
    1413  | 
     | 
     | 
    					break;  | 
    
    
    1414  | 
     | 
     | 
    				}  | 
    
    
    1415  | 
     | 
     | 
    				putchar('\n'); | 
    
    
    1416  | 
     | 
     | 
    			}  | 
    
    
    1417  | 
     | 
     | 
    			break;  | 
    
    
    1418  | 
     | 
     | 
    		case IPOPT_NOP:  | 
    
    
    1419  | 
     | 
     | 
    			printf("\nNOP"); | 
    
    
    1420  | 
     | 
     | 
    			break;  | 
    
    
    1421  | 
     | 
     | 
    		default:  | 
    
    
    1422  | 
     | 
     | 
    			printf("\nunknown option %x", *cp); | 
    
    
    1423  | 
     | 
     | 
    			hlen = hlen - (cp[IPOPT_OLEN] - 1);  | 
    
    
    1424  | 
     | 
     | 
    			cp = cp + (cp[IPOPT_OLEN] - 1);  | 
    
    
    1425  | 
     | 
     | 
    			break;  | 
    
    
    1426  | 
     | 
     | 
    		}  | 
    
    
    1427  | 
     | 
     | 
    	}  | 
    
    
    1428  | 
     | 
     | 
    }  | 
    
    
    1429  | 
     | 
     | 
     | 
    
    
    1430  | 
     | 
     | 
    /*  | 
    
    
    1431  | 
     | 
     | 
     * in_cksum --  | 
    
    
    1432  | 
     | 
     | 
     *	Checksum routine for Internet Protocol family headers (C Version)  | 
    
    
    1433  | 
     | 
     | 
     */  | 
    
    
    1434  | 
     | 
     | 
    int  | 
    
    
    1435  | 
     | 
     | 
    in_cksum(u_short *addr, int len)  | 
    
    
    1436  | 
     | 
     | 
    { | 
    
    
    1437  | 
     | 
     | 
    	int nleft = len;  | 
    
    
    1438  | 
     | 
     | 
    	u_short *w = addr;  | 
    
    
    1439  | 
     | 
     | 
    	int sum = 0;  | 
    
    
    1440  | 
     | 
     | 
    	u_short answer = 0;  | 
    
    
    1441  | 
     | 
     | 
     | 
    
    
    1442  | 
     | 
     | 
    	/*  | 
    
    
    1443  | 
     | 
     | 
    	 * Our algorithm is simple, using a 32 bit accumulator (sum), we add  | 
    
    
    1444  | 
     | 
     | 
    	 * sequential 16 bit words to it, and at the end, fold back all the  | 
    
    
    1445  | 
     | 
     | 
    	 * carry bits from the top 16 bits into the lower 16 bits.  | 
    
    
    1446  | 
     | 
     | 
    	 */  | 
    
    
    1447  | 
     | 
     | 
    	while (nleft > 1) { | 
    
    
    1448  | 
     | 
     | 
    		sum += *w++;  | 
    
    
    1449  | 
     | 
     | 
    		nleft -= 2;  | 
    
    
    1450  | 
     | 
     | 
    	}  | 
    
    
    1451  | 
     | 
     | 
     | 
    
    
    1452  | 
     | 
     | 
    	/* mop up an odd byte, if necessary */  | 
    
    
    1453  | 
     | 
     | 
    	if (nleft == 1) { | 
    
    
    1454  | 
     | 
     | 
    		*(u_char *)(&answer) = *(u_char *)w ;  | 
    
    
    1455  | 
     | 
     | 
    		sum += answer;  | 
    
    
    1456  | 
     | 
     | 
    	}  | 
    
    
    1457  | 
     | 
     | 
     | 
    
    
    1458  | 
     | 
     | 
    	/* add back carry outs from top 16 bits to low 16 bits */  | 
    
    
    1459  | 
     | 
     | 
    	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */  | 
    
    
    1460  | 
     | 
     | 
    	sum += (sum >> 16);			/* add carry */  | 
    
    
    1461  | 
     | 
     | 
    	answer = ~sum;				/* truncate to 16 bits */  | 
    
    
    1462  | 
     | 
     | 
    	return(answer);  | 
    
    
    1463  | 
     | 
     | 
    }  | 
    
    
    1464  | 
     | 
     | 
     | 
    
    
    1465  | 
     | 
     | 
    /*  | 
    
    
    1466  | 
     | 
     | 
     * pr_icmph --  | 
    
    
    1467  | 
     | 
     | 
     *	Print a descriptive string about an ICMP header.  | 
    
    
    1468  | 
     | 
     | 
     */  | 
    
    
    1469  | 
     | 
     | 
    void  | 
    
    
    1470  | 
     | 
     | 
    pr_icmph(struct icmp *icp)  | 
    
    
    1471  | 
     | 
     | 
    { | 
    
    
    1472  | 
     | 
     | 
    	switch(icp->icmp_type) { | 
    
    
    1473  | 
     | 
     | 
    	case ICMP_ECHOREPLY:  | 
    
    
    1474  | 
     | 
     | 
    		printf("Echo Reply\n"); | 
    
    
    1475  | 
     | 
     | 
    		/* XXX ID + Seq + Data */  | 
    
    
    1476  | 
     | 
     | 
    		break;  | 
    
    
    1477  | 
     | 
     | 
    	case ICMP_UNREACH:  | 
    
    
    1478  | 
     | 
     | 
    		switch(icp->icmp_code) { | 
    
    
    1479  | 
     | 
     | 
    		case ICMP_UNREACH_NET:  | 
    
    
    1480  | 
     | 
     | 
    			printf("Destination Net Unreachable\n"); | 
    
    
    1481  | 
     | 
     | 
    			break;  | 
    
    
    1482  | 
     | 
     | 
    		case ICMP_UNREACH_HOST:  | 
    
    
    1483  | 
     | 
     | 
    			printf("Destination Host Unreachable\n"); | 
    
    
    1484  | 
     | 
     | 
    			break;  | 
    
    
    1485  | 
     | 
     | 
    		case ICMP_UNREACH_PROTOCOL:  | 
    
    
    1486  | 
     | 
     | 
    			printf("Destination Protocol Unreachable\n"); | 
    
    
    1487  | 
     | 
     | 
    			break;  | 
    
    
    1488  | 
     | 
     | 
    		case ICMP_UNREACH_PORT:  | 
    
    
    1489  | 
     | 
     | 
    			printf("Destination Port Unreachable\n"); | 
    
    
    1490  | 
     | 
     | 
    			break;  | 
    
    
    1491  | 
     | 
     | 
    		case ICMP_UNREACH_NEEDFRAG:  | 
    
    
    1492  | 
     | 
     | 
    			if (icp->icmp_nextmtu != 0)  | 
    
    
    1493  | 
     | 
     | 
    				printf("frag needed and DF set (MTU %d)\n", | 
    
    
    1494  | 
     | 
     | 
    				    ntohs(icp->icmp_nextmtu));  | 
    
    
    1495  | 
     | 
     | 
    			else  | 
    
    
    1496  | 
     | 
     | 
    				printf("frag needed and DF set\n"); | 
    
    
    1497  | 
     | 
     | 
    			break;  | 
    
    
    1498  | 
     | 
     | 
    		case ICMP_UNREACH_SRCFAIL:  | 
    
    
    1499  | 
     | 
     | 
    			printf("Source Route Failed\n"); | 
    
    
    1500  | 
     | 
     | 
    			break;  | 
    
    
    1501  | 
     | 
     | 
    		case ICMP_UNREACH_NET_UNKNOWN:  | 
    
    
    1502  | 
     | 
     | 
    			printf("Network Unknown\n"); | 
    
    
    1503  | 
     | 
     | 
    			break;  | 
    
    
    1504  | 
     | 
     | 
    		case ICMP_UNREACH_HOST_UNKNOWN:  | 
    
    
    1505  | 
     | 
     | 
    			printf("Host Unknown\n"); | 
    
    
    1506  | 
     | 
     | 
    			break;  | 
    
    
    1507  | 
     | 
     | 
    		case ICMP_UNREACH_ISOLATED:  | 
    
    
    1508  | 
     | 
     | 
    			printf("Source Isolated\n"); | 
    
    
    1509  | 
     | 
     | 
    			break;  | 
    
    
    1510  | 
     | 
     | 
    		case ICMP_UNREACH_NET_PROHIB:  | 
    
    
    1511  | 
     | 
     | 
    			printf("Dest. Net Administratively Prohibited\n"); | 
    
    
    1512  | 
     | 
     | 
    			break;  | 
    
    
    1513  | 
     | 
     | 
    		case ICMP_UNREACH_HOST_PROHIB:  | 
    
    
    1514  | 
     | 
     | 
    			printf("Dest. Host Administratively Prohibited\n"); | 
    
    
    1515  | 
     | 
     | 
    			break;  | 
    
    
    1516  | 
     | 
     | 
    		case ICMP_UNREACH_TOSNET:  | 
    
    
    1517  | 
     | 
     | 
    			printf("Destination Net Unreachable for TOS\n"); | 
    
    
    1518  | 
     | 
     | 
    			break;  | 
    
    
    1519  | 
     | 
     | 
    		case ICMP_UNREACH_TOSHOST:  | 
    
    
    1520  | 
     | 
     | 
    			printf("Destination Host Unreachable for TOS\n"); | 
    
    
    1521  | 
     | 
     | 
    			break;  | 
    
    
    1522  | 
     | 
     | 
    		case ICMP_UNREACH_FILTER_PROHIB:  | 
    
    
    1523  | 
     | 
     | 
    			printf("Route administratively prohibited\n"); | 
    
    
    1524  | 
     | 
     | 
    			break;  | 
    
    
    1525  | 
     | 
     | 
    		case ICMP_UNREACH_HOST_PRECEDENCE:  | 
    
    
    1526  | 
     | 
     | 
    			printf("Host Precedence Violation\n"); | 
    
    
    1527  | 
     | 
     | 
    			break;  | 
    
    
    1528  | 
     | 
     | 
    		case ICMP_UNREACH_PRECEDENCE_CUTOFF:  | 
    
    
    1529  | 
     | 
     | 
    			printf("Precedence Cutoff\n"); | 
    
    
    1530  | 
     | 
     | 
    			break;  | 
    
    
    1531  | 
     | 
     | 
    		default:  | 
    
    
    1532  | 
     | 
     | 
    			printf("Dest Unreachable, Unknown Code: %d\n", | 
    
    
    1533  | 
     | 
     | 
    			    icp->icmp_code);  | 
    
    
    1534  | 
     | 
     | 
    			break;  | 
    
    
    1535  | 
     | 
     | 
    		}  | 
    
    
    1536  | 
     | 
     | 
    		/* Print returned IP header information */  | 
    
    
    1537  | 
     | 
     | 
    		pr_retip((struct ip *)icp->icmp_data);  | 
    
    
    1538  | 
     | 
     | 
    		break;  | 
    
    
    1539  | 
     | 
     | 
    	case ICMP_SOURCEQUENCH:  | 
    
    
    1540  | 
     | 
     | 
    		printf("Source Quench\n"); | 
    
    
    1541  | 
     | 
     | 
    		pr_retip((struct ip *)icp->icmp_data);  | 
    
    
    1542  | 
     | 
     | 
    		break;  | 
    
    
    1543  | 
     | 
     | 
    	case ICMP_REDIRECT:  | 
    
    
    1544  | 
     | 
     | 
    		switch(icp->icmp_code) { | 
    
    
    1545  | 
     | 
     | 
    		case ICMP_REDIRECT_NET:  | 
    
    
    1546  | 
     | 
     | 
    			printf("Redirect Network"); | 
    
    
    1547  | 
     | 
     | 
    			break;  | 
    
    
    1548  | 
     | 
     | 
    		case ICMP_REDIRECT_HOST:  | 
    
    
    1549  | 
     | 
     | 
    			printf("Redirect Host"); | 
    
    
    1550  | 
     | 
     | 
    			break;  | 
    
    
    1551  | 
     | 
     | 
    		case ICMP_REDIRECT_TOSNET:  | 
    
    
    1552  | 
     | 
     | 
    			printf("Redirect Type of Service and Network"); | 
    
    
    1553  | 
     | 
     | 
    			break;  | 
    
    
    1554  | 
     | 
     | 
    		case ICMP_REDIRECT_TOSHOST:  | 
    
    
    1555  | 
     | 
     | 
    			printf("Redirect Type of Service and Host"); | 
    
    
    1556  | 
     | 
     | 
    			break;  | 
    
    
    1557  | 
     | 
     | 
    		default:  | 
    
    
    1558  | 
     | 
     | 
    			printf("Redirect, Unknown Code: %d", icp->icmp_code); | 
    
    
    1559  | 
     | 
     | 
    			break;  | 
    
    
    1560  | 
     | 
     | 
    		}  | 
    
    
    1561  | 
     | 
     | 
    		printf("(New addr: %s)\n", | 
    
    
    1562  | 
     | 
     | 
    		    inet_ntoa(icp->icmp_gwaddr));  | 
    
    
    1563  | 
     | 
     | 
    		pr_retip((struct ip *)icp->icmp_data);  | 
    
    
    1564  | 
     | 
     | 
    		break;  | 
    
    
    1565  | 
     | 
     | 
    	case ICMP_ECHO:  | 
    
    
    1566  | 
     | 
     | 
    		printf("Echo Request\n"); | 
    
    
    1567  | 
     | 
     | 
    		/* XXX ID + Seq + Data */  | 
    
    
    1568  | 
     | 
     | 
    		break;  | 
    
    
    1569  | 
     | 
     | 
    	case ICMP_ROUTERADVERT:  | 
    
    
    1570  | 
     | 
     | 
    		/* RFC1256 */  | 
    
    
    1571  | 
     | 
     | 
    		printf("Router Discovery Advertisement\n"); | 
    
    
    1572  | 
     | 
     | 
    		printf("(%d entries, lifetime %d seconds)\n", | 
    
    
    1573  | 
     | 
     | 
    		    icp->icmp_num_addrs, ntohs(icp->icmp_lifetime));  | 
    
    
    1574  | 
     | 
     | 
    		break;  | 
    
    
    1575  | 
     | 
     | 
    	case ICMP_ROUTERSOLICIT:  | 
    
    
    1576  | 
     | 
     | 
    		/* RFC1256 */  | 
    
    
    1577  | 
     | 
     | 
    		printf("Router Discovery Solicitation\n"); | 
    
    
    1578  | 
     | 
     | 
    		break;  | 
    
    
    1579  | 
     | 
     | 
    	case ICMP_TIMXCEED:  | 
    
    
    1580  | 
     | 
     | 
    		switch(icp->icmp_code) { | 
    
    
    1581  | 
     | 
     | 
    		case ICMP_TIMXCEED_INTRANS:  | 
    
    
    1582  | 
     | 
     | 
    			printf("Time to live exceeded\n"); | 
    
    
    1583  | 
     | 
     | 
    			break;  | 
    
    
    1584  | 
     | 
     | 
    		case ICMP_TIMXCEED_REASS:  | 
    
    
    1585  | 
     | 
     | 
    			printf("Frag reassembly time exceeded\n"); | 
    
    
    1586  | 
     | 
     | 
    			break;  | 
    
    
    1587  | 
     | 
     | 
    		default:  | 
    
    
    1588  | 
     | 
     | 
    			printf("Time exceeded, Unknown Code: %d\n", | 
    
    
    1589  | 
     | 
     | 
    			    icp->icmp_code);  | 
    
    
    1590  | 
     | 
     | 
    			break;  | 
    
    
    1591  | 
     | 
     | 
    		}  | 
    
    
    1592  | 
     | 
     | 
    		pr_retip((struct ip *)icp->icmp_data);  | 
    
    
    1593  | 
     | 
     | 
    		break;  | 
    
    
    1594  | 
     | 
     | 
    	case ICMP_PARAMPROB:  | 
    
    
    1595  | 
     | 
     | 
    		switch(icp->icmp_code) { | 
    
    
    1596  | 
     | 
     | 
    		case ICMP_PARAMPROB_OPTABSENT:  | 
    
    
    1597  | 
     | 
     | 
    			printf("Parameter problem, required option " | 
    
    
    1598  | 
     | 
     | 
    			    "absent: pointer = 0x%02x\n",  | 
    
    
    1599  | 
     | 
     | 
    			    ntohs(icp->icmp_hun.ih_pptr));  | 
    
    
    1600  | 
     | 
     | 
    			break;  | 
    
    
    1601  | 
     | 
     | 
    		default:  | 
    
    
    1602  | 
     | 
     | 
    			printf("Parameter problem: pointer = 0x%02x\n", | 
    
    
    1603  | 
     | 
     | 
    			    ntohs(icp->icmp_hun.ih_pptr));  | 
    
    
    1604  | 
     | 
     | 
    			break;  | 
    
    
    1605  | 
     | 
     | 
    		}  | 
    
    
    1606  | 
     | 
     | 
    		pr_retip((struct ip *)icp->icmp_data);  | 
    
    
    1607  | 
     | 
     | 
    		break;  | 
    
    
    1608  | 
     | 
     | 
    	case ICMP_TSTAMP:  | 
    
    
    1609  | 
     | 
     | 
    		printf("Timestamp\n"); | 
    
    
    1610  | 
     | 
     | 
    		/* XXX ID + Seq + 3 timestamps */  | 
    
    
    1611  | 
     | 
     | 
    		break;  | 
    
    
    1612  | 
     | 
     | 
    	case ICMP_TSTAMPREPLY:  | 
    
    
    1613  | 
     | 
     | 
    		printf("Timestamp Reply\n"); | 
    
    
    1614  | 
     | 
     | 
    		/* XXX ID + Seq + 3 timestamps */  | 
    
    
    1615  | 
     | 
     | 
    		break;  | 
    
    
    1616  | 
     | 
     | 
    	case ICMP_IREQ:  | 
    
    
    1617  | 
     | 
     | 
    		printf("Information Request\n"); | 
    
    
    1618  | 
     | 
     | 
    		/* XXX ID + Seq */  | 
    
    
    1619  | 
     | 
     | 
    		break;  | 
    
    
    1620  | 
     | 
     | 
    	case ICMP_IREQREPLY:  | 
    
    
    1621  | 
     | 
     | 
    		printf("Information Reply\n"); | 
    
    
    1622  | 
     | 
     | 
    		/* XXX ID + Seq */  | 
    
    
    1623  | 
     | 
     | 
    		break;  | 
    
    
    1624  | 
     | 
     | 
    	case ICMP_MASKREQ:  | 
    
    
    1625  | 
     | 
     | 
    		printf("Address Mask Request\n"); | 
    
    
    1626  | 
     | 
     | 
    		break;  | 
    
    
    1627  | 
     | 
     | 
    	case ICMP_MASKREPLY:  | 
    
    
    1628  | 
     | 
     | 
    		printf("Address Mask Reply (Mask 0x%08x)\n", | 
    
    
    1629  | 
     | 
     | 
    		    ntohl(icp->icmp_mask));  | 
    
    
    1630  | 
     | 
     | 
    		break;  | 
    
    
    1631  | 
     | 
     | 
    	default:  | 
    
    
    1632  | 
     | 
     | 
    		printf("Unknown ICMP type: %d\n", icp->icmp_type); | 
    
    
    1633  | 
     | 
     | 
    	}  | 
    
    
    1634  | 
     | 
     | 
    }  | 
    
    
    1635  | 
     | 
     | 
     | 
    
    
    1636  | 
     | 
     | 
    /*  | 
    
    
    1637  | 
     | 
     | 
     * pr_iph --  | 
    
    
    1638  | 
     | 
     | 
     *	Print an IP header with options.  | 
    
    
    1639  | 
     | 
     | 
     */  | 
    
    
    1640  | 
     | 
     | 
    void  | 
    
    
    1641  | 
     | 
     | 
    pr_iph(struct ip *ip)  | 
    
    
    1642  | 
     | 
     | 
    { | 
    
    
    1643  | 
     | 
     | 
    	int hlen;  | 
    
    
    1644  | 
     | 
     | 
    	u_char *cp;  | 
    
    
    1645  | 
     | 
     | 
     | 
    
    
    1646  | 
     | 
     | 
    	hlen = ip->ip_hl << 2;  | 
    
    
    1647  | 
     | 
     | 
    	cp = (u_char *)ip + 20;		/* point to options */  | 
    
    
    1648  | 
     | 
     | 
     | 
    
    
    1649  | 
     | 
     | 
    	printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n"); | 
    
    
    1650  | 
     | 
     | 
    	printf(" %1x  %1x  %02x %04x %04x", | 
    
    
    1651  | 
     | 
     | 
    	    ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);  | 
    
    
    1652  | 
     | 
     | 
    	printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13, | 
    
    
    1653  | 
     | 
     | 
    	    (ip->ip_off) & 0x1fff);  | 
    
    
    1654  | 
     | 
     | 
    	printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); | 
    
    
    1655  | 
     | 
     | 
    	printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); | 
    
    
    1656  | 
     | 
     | 
    	printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); | 
    
    
    1657  | 
     | 
     | 
    	/* dump and option bytes */  | 
    
    
    1658  | 
     | 
     | 
    	while (hlen-- > 20) { | 
    
    
    1659  | 
     | 
     | 
    		printf("%02x", *cp++); | 
    
    
    1660  | 
     | 
     | 
    	}  | 
    
    
    1661  | 
     | 
     | 
    	putchar('\n'); | 
    
    
    1662  | 
     | 
     | 
    }  | 
    
    
    1663  | 
     | 
     | 
     | 
    
    
    1664  | 
     | 
     | 
    /*  | 
    
    
    1665  | 
     | 
     | 
     * pr_retip --  | 
    
    
    1666  | 
     | 
     | 
     *	Dump some info on a returned (via ICMP) IP packet.  | 
    
    
    1667  | 
     | 
     | 
     */  | 
    
    
    1668  | 
     | 
     | 
    void  | 
    
    
    1669  | 
     | 
     | 
    pr_retip(struct ip *ip)  | 
    
    
    1670  | 
     | 
     | 
    { | 
    
    
    1671  | 
     | 
     | 
    	int hlen;  | 
    
    
    1672  | 
     | 
     | 
    	u_char *cp;  | 
    
    
    1673  | 
     | 
     | 
     | 
    
    
    1674  | 
     | 
     | 
    	pr_iph(ip);  | 
    
    
    1675  | 
     | 
     | 
    	hlen = ip->ip_hl << 2;  | 
    
    
    1676  | 
     | 
     | 
    	cp = (u_char *)ip + hlen;  | 
    
    
    1677  | 
     | 
     | 
     | 
    
    
    1678  | 
     | 
     | 
    	if (ip->ip_p == 6)  | 
    
    
    1679  | 
     | 
     | 
    		printf("TCP: from port %u, to port %u (decimal)\n", | 
    
    
    1680  | 
     | 
     | 
    		    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));  | 
    
    
    1681  | 
     | 
     | 
    	else if (ip->ip_p == 17)  | 
    
    
    1682  | 
     | 
     | 
    		printf("UDP: from port %u, to port %u (decimal)\n", | 
    
    
    1683  | 
     | 
     | 
    		    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));  | 
    
    
    1684  | 
     | 
     | 
    }  | 
    
    
    1685  | 
     | 
     | 
     | 
    
    
    1686  | 
     | 
     | 
    #ifndef SMALL  | 
    
    
    1687  | 
     | 
     | 
    int  | 
    
    
    1688  | 
     | 
     | 
    map_tos(char *key, int *val)  | 
    
    
    1689  | 
     | 
     | 
    { | 
    
    
    1690  | 
     | 
     | 
    	/* DiffServ Codepoints and other TOS mappings */  | 
    
    
    1691  | 
     | 
     | 
    	const struct toskeywords { | 
    
    
    1692  | 
     | 
     | 
    		const char	*keyword;  | 
    
    
    1693  | 
     | 
     | 
    		int		 val;  | 
    
    
    1694  | 
     | 
     | 
    	} *t, toskeywords[] = { | 
    
    
    1695  | 
     | 
     | 
    		{ "af11",		IPTOS_DSCP_AF11 }, | 
    
    
    1696  | 
     | 
     | 
    		{ "af12",		IPTOS_DSCP_AF12 }, | 
    
    
    1697  | 
     | 
     | 
    		{ "af13",		IPTOS_DSCP_AF13 }, | 
    
    
    1698  | 
     | 
     | 
    		{ "af21",		IPTOS_DSCP_AF21 }, | 
    
    
    1699  | 
     | 
     | 
    		{ "af22",		IPTOS_DSCP_AF22 }, | 
    
    
    1700  | 
     | 
     | 
    		{ "af23",		IPTOS_DSCP_AF23 }, | 
    
    
    1701  | 
     | 
     | 
    		{ "af31",		IPTOS_DSCP_AF31 }, | 
    
    
    1702  | 
     | 
     | 
    		{ "af32",		IPTOS_DSCP_AF32 }, | 
    
    
    1703  | 
     | 
     | 
    		{ "af33",		IPTOS_DSCP_AF33 }, | 
    
    
    1704  | 
     | 
     | 
    		{ "af41",		IPTOS_DSCP_AF41 }, | 
    
    
    1705  | 
     | 
     | 
    		{ "af42",		IPTOS_DSCP_AF42 }, | 
    
    
    1706  | 
     | 
     | 
    		{ "af43",		IPTOS_DSCP_AF43 }, | 
    
    
    1707  | 
     | 
     | 
    		{ "critical",		IPTOS_PREC_CRITIC_ECP }, | 
    
    
    1708  | 
     | 
     | 
    		{ "cs0",		IPTOS_DSCP_CS0 }, | 
    
    
    1709  | 
     | 
     | 
    		{ "cs1",		IPTOS_DSCP_CS1 }, | 
    
    
    1710  | 
     | 
     | 
    		{ "cs2",		IPTOS_DSCP_CS2 }, | 
    
    
    1711  | 
     | 
     | 
    		{ "cs3",		IPTOS_DSCP_CS3 }, | 
    
    
    1712  | 
     | 
     | 
    		{ "cs4",		IPTOS_DSCP_CS4 }, | 
    
    
    1713  | 
     | 
     | 
    		{ "cs5",		IPTOS_DSCP_CS5 }, | 
    
    
    1714  | 
     | 
     | 
    		{ "cs6",		IPTOS_DSCP_CS6 }, | 
    
    
    1715  | 
     | 
     | 
    		{ "cs7",		IPTOS_DSCP_CS7 }, | 
    
    
    1716  | 
     | 
     | 
    		{ "ef",			IPTOS_DSCP_EF }, | 
    
    
    1717  | 
     | 
     | 
    		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL }, | 
    
    
    1718  | 
     | 
     | 
    		{ "lowdelay",		IPTOS_LOWDELAY }, | 
    
    
    1719  | 
     | 
     | 
    		{ "netcontrol",		IPTOS_PREC_NETCONTROL }, | 
    
    
    1720  | 
     | 
     | 
    		{ "reliability",	IPTOS_RELIABILITY }, | 
    
    
    1721  | 
     | 
     | 
    		{ "throughput",		IPTOS_THROUGHPUT }, | 
    
    
    1722  | 
     | 
     | 
    		{ NULL,			-1 }, | 
    
    
    1723  | 
     | 
     | 
    	};  | 
    
    
    1724  | 
     | 
     | 
     | 
    
    
    1725  | 
     | 
     | 
    	for (t = toskeywords; t->keyword != NULL; t++) { | 
    
    
    1726  | 
     | 
     | 
    		if (strcmp(key, t->keyword) == 0) { | 
    
    
    1727  | 
     | 
     | 
    			*val = t->val;  | 
    
    
    1728  | 
     | 
     | 
    			return (1);  | 
    
    
    1729  | 
     | 
     | 
    		}  | 
    
    
    1730  | 
     | 
     | 
    	}  | 
    
    
    1731  | 
     | 
     | 
     | 
    
    
    1732  | 
     | 
     | 
    	return (0);  | 
    
    
    1733  | 
     | 
     | 
    }  | 
    
    
    1734  | 
     | 
     | 
    #endif	/* SMALL */  | 
    
    
    1735  | 
     | 
     | 
     | 
    
    
    1736  | 
     | 
     | 
    void  | 
    
    
    1737  | 
     | 
     | 
    pr_exthdrs(struct msghdr *mhdr)  | 
    
    
    1738  | 
     | 
     | 
    { | 
    
    
    1739  | 
     | 
     | 
    	struct cmsghdr *cm;  | 
    
    
    1740  | 
     | 
     | 
     | 
    
    
    1741  | 
     | 
     | 
    	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;  | 
    
    
    1742  | 
     | 
     | 
    	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { | 
    
    
    1743  | 
     | 
     | 
    		if (cm->cmsg_level != IPPROTO_IPV6)  | 
    
    
    1744  | 
     | 
     | 
    			continue;  | 
    
    
    1745  | 
     | 
     | 
     | 
    
    
    1746  | 
     | 
     | 
    		switch (cm->cmsg_type) { | 
    
    
    1747  | 
     | 
     | 
    		case IPV6_HOPOPTS:  | 
    
    
    1748  | 
     | 
     | 
    			printf("  HbH Options: "); | 
    
    
    1749  | 
     | 
     | 
    			pr_ip6opt(CMSG_DATA(cm));  | 
    
    
    1750  | 
     | 
     | 
    			break;  | 
    
    
    1751  | 
     | 
     | 
    		case IPV6_DSTOPTS:  | 
    
    
    1752  | 
     | 
     | 
    		case IPV6_RTHDRDSTOPTS:  | 
    
    
    1753  | 
     | 
     | 
    			printf("  Dst Options: "); | 
    
    
    1754  | 
     | 
     | 
    			pr_ip6opt(CMSG_DATA(cm));  | 
    
    
    1755  | 
     | 
     | 
    			break;  | 
    
    
    1756  | 
     | 
     | 
    		case IPV6_RTHDR:  | 
    
    
    1757  | 
     | 
     | 
    			printf("  Routing: "); | 
    
    
    1758  | 
     | 
     | 
    			pr_rthdr(CMSG_DATA(cm));  | 
    
    
    1759  | 
     | 
     | 
    			break;  | 
    
    
    1760  | 
     | 
     | 
    		}  | 
    
    
    1761  | 
     | 
     | 
    	}  | 
    
    
    1762  | 
     | 
     | 
    }  | 
    
    
    1763  | 
     | 
     | 
     | 
    
    
    1764  | 
     | 
     | 
    void  | 
    
    
    1765  | 
     | 
     | 
    pr_ip6opt(void *extbuf)  | 
    
    
    1766  | 
     | 
     | 
    { | 
    
    
    1767  | 
     | 
     | 
    	struct ip6_hbh *ext;  | 
    
    
    1768  | 
     | 
     | 
    	int currentlen;  | 
    
    
    1769  | 
     | 
     | 
    	u_int8_t type;  | 
    
    
    1770  | 
     | 
     | 
    	size_t extlen;  | 
    
    
    1771  | 
     | 
     | 
    	socklen_t len;  | 
    
    
    1772  | 
     | 
     | 
    	void *databuf;  | 
    
    
    1773  | 
     | 
     | 
    	u_int16_t value2;  | 
    
    
    1774  | 
     | 
     | 
    	u_int32_t value4;  | 
    
    
    1775  | 
     | 
     | 
     | 
    
    
    1776  | 
     | 
     | 
    	ext = (struct ip6_hbh *)extbuf;  | 
    
    
    1777  | 
     | 
     | 
    	extlen = (ext->ip6h_len + 1) * 8;  | 
    
    
    1778  | 
     | 
     | 
    	printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, | 
    
    
    1779  | 
     | 
     | 
    	    (unsigned int)ext->ip6h_len, (unsigned long)extlen);  | 
    
    
    1780  | 
     | 
     | 
     | 
    
    
    1781  | 
     | 
     | 
    	currentlen = 0;  | 
    
    
    1782  | 
     | 
     | 
    	while (1) { | 
    
    
    1783  | 
     | 
     | 
    		currentlen = inet6_opt_next(extbuf, extlen, currentlen,  | 
    
    
    1784  | 
     | 
     | 
    		    &type, &len, &databuf);  | 
    
    
    1785  | 
     | 
     | 
    		if (currentlen == -1)  | 
    
    
    1786  | 
     | 
     | 
    			break;  | 
    
    
    1787  | 
     | 
     | 
    		switch (type) { | 
    
    
    1788  | 
     | 
     | 
    		/*  | 
    
    
    1789  | 
     | 
     | 
    		 * Note that inet6_opt_next automatically skips any padding  | 
    
    
    1790  | 
     | 
     | 
    		 * options.  | 
    
    
    1791  | 
     | 
     | 
    		 */  | 
    
    
    1792  | 
     | 
     | 
    		case IP6OPT_JUMBO:  | 
    
    
    1793  | 
     | 
     | 
    			inet6_opt_get_val(databuf, 0, &value4, sizeof(value4));  | 
    
    
    1794  | 
     | 
     | 
    			printf("    Jumbo Payload Opt: Length %u\n", | 
    
    
    1795  | 
     | 
     | 
    			    (u_int32_t)ntohl(value4));  | 
    
    
    1796  | 
     | 
     | 
    			break;  | 
    
    
    1797  | 
     | 
     | 
    		case IP6OPT_ROUTER_ALERT:  | 
    
    
    1798  | 
     | 
     | 
    			inet6_opt_get_val(databuf, 0, &value2, sizeof(value2));  | 
    
    
    1799  | 
     | 
     | 
    			printf("    Router Alert Opt: Type %u\n", | 
    
    
    1800  | 
     | 
     | 
    			    ntohs(value2));  | 
    
    
    1801  | 
     | 
     | 
    			break;  | 
    
    
    1802  | 
     | 
     | 
    		default:  | 
    
    
    1803  | 
     | 
     | 
    			printf("    Received Opt %u len %lu\n", | 
    
    
    1804  | 
     | 
     | 
    			    type, (unsigned long)len);  | 
    
    
    1805  | 
     | 
     | 
    			break;  | 
    
    
    1806  | 
     | 
     | 
    		}  | 
    
    
    1807  | 
     | 
     | 
    	}  | 
    
    
    1808  | 
     | 
     | 
    	return;  | 
    
    
    1809  | 
     | 
     | 
    }  | 
    
    
    1810  | 
     | 
     | 
     | 
    
    
    1811  | 
     | 
     | 
    void  | 
    
    
    1812  | 
     | 
     | 
    pr_rthdr(void *extbuf)  | 
    
    
    1813  | 
     | 
     | 
    { | 
    
    
    1814  | 
     | 
     | 
    	struct in6_addr *in6;  | 
    
    
    1815  | 
     | 
     | 
    	char ntopbuf[INET6_ADDRSTRLEN];  | 
    
    
    1816  | 
     | 
     | 
    	struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;  | 
    
    
    1817  | 
     | 
     | 
    	int i, segments;  | 
    
    
    1818  | 
     | 
     | 
     | 
    
    
    1819  | 
     | 
     | 
    	/* print fixed part of the header */  | 
    
    
    1820  | 
     | 
     | 
    	printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, | 
    
    
    1821  | 
     | 
     | 
    	    rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);  | 
    
    
    1822  | 
     | 
     | 
    	if ((segments = inet6_rth_segments(extbuf)) >= 0)  | 
    
    
    1823  | 
     | 
     | 
    		printf("%d segments, ", segments); | 
    
    
    1824  | 
     | 
     | 
    	else  | 
    
    
    1825  | 
     | 
     | 
    		printf("segments unknown, "); | 
    
    
    1826  | 
     | 
     | 
    	printf("%d left\n", rh->ip6r_segleft); | 
    
    
    1827  | 
     | 
     | 
     | 
    
    
    1828  | 
     | 
     | 
    	for (i = 0; i < segments; i++) { | 
    
    
    1829  | 
     | 
     | 
    		in6 = inet6_rth_getaddr(extbuf, i);  | 
    
    
    1830  | 
     | 
     | 
    		if (in6 == NULL)  | 
    
    
    1831  | 
     | 
     | 
    			printf("   [%d]<NULL>\n", i); | 
    
    
    1832  | 
     | 
     | 
    		else { | 
    
    
    1833  | 
     | 
     | 
    			if (!inet_ntop(AF_INET6, in6, ntopbuf,  | 
    
    
    1834  | 
     | 
     | 
    			    sizeof(ntopbuf)))  | 
    
    
    1835  | 
     | 
     | 
    				strncpy(ntopbuf, "?", sizeof(ntopbuf));  | 
    
    
    1836  | 
     | 
     | 
    			printf("   [%d]%s\n", i, ntopbuf); | 
    
    
    1837  | 
     | 
     | 
    		}  | 
    
    
    1838  | 
     | 
     | 
    	}  | 
    
    
    1839  | 
     | 
     | 
     | 
    
    
    1840  | 
     | 
     | 
    	return;  | 
    
    
    1841  | 
     | 
     | 
     | 
    
    
    1842  | 
     | 
     | 
    }  | 
    
    
    1843  | 
     | 
     | 
     | 
    
    
    1844  | 
     | 
     | 
    int  | 
    
    
    1845  | 
     | 
     | 
    get_hoplim(struct msghdr *mhdr)  | 
    
    
    1846  | 
     | 
     | 
    { | 
    
    
    1847  | 
     | 
     | 
    	struct cmsghdr *cm;  | 
    
    
    1848  | 
     | 
     | 
     | 
    
    
    1849  | 
     | 
     | 
    	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;  | 
    
    
    1850  | 
     | 
     | 
    	     cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { | 
    
    
    1851  | 
     | 
     | 
    		if (cm->cmsg_len == 0)  | 
    
    
    1852  | 
     | 
     | 
    			return(-1);  | 
    
    
    1853  | 
     | 
     | 
     | 
    
    
    1854  | 
     | 
     | 
    		if (cm->cmsg_level == IPPROTO_IPV6 &&  | 
    
    
    1855  | 
     | 
     | 
    		    cm->cmsg_type == IPV6_HOPLIMIT &&  | 
    
    
    1856  | 
     | 
     | 
    		    cm->cmsg_len == CMSG_LEN(sizeof(int)))  | 
    
    
    1857  | 
     | 
     | 
    			return(*(int *)CMSG_DATA(cm));  | 
    
    
    1858  | 
     | 
     | 
    	}  | 
    
    
    1859  | 
     | 
     | 
     | 
    
    
    1860  | 
     | 
     | 
    	return(-1);  | 
    
    
    1861  | 
     | 
     | 
    }  | 
    
    
    1862  | 
     | 
     | 
     | 
    
    
    1863  | 
     | 
     | 
    int  | 
    
    
    1864  | 
     | 
     | 
    get_pathmtu(struct msghdr *mhdr, struct sockaddr_in6 *dst)  | 
    
    
    1865  | 
     | 
     | 
    { | 
    
    
    1866  | 
     | 
     | 
    	struct cmsghdr *cm;  | 
    
    
    1867  | 
     | 
     | 
    	struct ip6_mtuinfo *mtuctl = NULL;  | 
    
    
    1868  | 
     | 
     | 
     | 
    
    
    1869  | 
     | 
     | 
    	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;  | 
    
    
    1870  | 
     | 
     | 
    	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { | 
    
    
    1871  | 
     | 
     | 
    		if (cm->cmsg_len == 0)  | 
    
    
    1872  | 
     | 
     | 
    			return(0);  | 
    
    
    1873  | 
     | 
     | 
     | 
    
    
    1874  | 
     | 
     | 
    		if (cm->cmsg_level == IPPROTO_IPV6 &&  | 
    
    
    1875  | 
     | 
     | 
    		    cm->cmsg_type == IPV6_PATHMTU &&  | 
    
    
    1876  | 
     | 
     | 
    		    cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { | 
    
    
    1877  | 
     | 
     | 
    			mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm);  | 
    
    
    1878  | 
     | 
     | 
     | 
    
    
    1879  | 
     | 
     | 
    			/*  | 
    
    
    1880  | 
     | 
     | 
    			 * If the notified destination is different from  | 
    
    
    1881  | 
     | 
     | 
    			 * the one we are pinging, just ignore the info.  | 
    
    
    1882  | 
     | 
     | 
    			 * We check the scope ID only when both notified value  | 
    
    
    1883  | 
     | 
     | 
    			 * and our own value have non-0 values, because we may  | 
    
    
    1884  | 
     | 
     | 
    			 * have used the default scope zone ID for sending,  | 
    
    
    1885  | 
     | 
     | 
    			 * in which case the scope ID value is 0.  | 
    
    
    1886  | 
     | 
     | 
    			 */  | 
    
    
    1887  | 
     | 
     | 
    			if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr,  | 
    
    
    1888  | 
     | 
     | 
    			    &dst->sin6_addr) ||  | 
    
    
    1889  | 
     | 
     | 
    			    (mtuctl->ip6m_addr.sin6_scope_id &&  | 
    
    
    1890  | 
     | 
     | 
    			    dst->sin6_scope_id &&  | 
    
    
    1891  | 
     | 
     | 
    			    mtuctl->ip6m_addr.sin6_scope_id !=  | 
    
    
    1892  | 
     | 
     | 
    			    dst->sin6_scope_id)) { | 
    
    
    1893  | 
     | 
     | 
    				if (options & F_VERBOSE) { | 
    
    
    1894  | 
     | 
     | 
    					printf("path MTU for %s is notified. " | 
    
    
    1895  | 
     | 
     | 
    					    "(ignored)\n",  | 
    
    
    1896  | 
     | 
     | 
    					    pr_addr((struct sockaddr *)  | 
    
    
    1897  | 
     | 
     | 
    					    &mtuctl->ip6m_addr,  | 
    
    
    1898  | 
     | 
     | 
    					    sizeof(mtuctl->ip6m_addr)));  | 
    
    
    1899  | 
     | 
     | 
    				}  | 
    
    
    1900  | 
     | 
     | 
    				return(0);  | 
    
    
    1901  | 
     | 
     | 
    			}  | 
    
    
    1902  | 
     | 
     | 
     | 
    
    
    1903  | 
     | 
     | 
    			/*  | 
    
    
    1904  | 
     | 
     | 
    			 * Ignore an invalid MTU. XXX: can we just believe  | 
    
    
    1905  | 
     | 
     | 
    			 * the kernel check?  | 
    
    
    1906  | 
     | 
     | 
    			 */  | 
    
    
    1907  | 
     | 
     | 
    			if (mtuctl->ip6m_mtu < IPV6_MMTU)  | 
    
    
    1908  | 
     | 
     | 
    				return(0);  | 
    
    
    1909  | 
     | 
     | 
     | 
    
    
    1910  | 
     | 
     | 
    			/* notification for our destination. return the MTU. */  | 
    
    
    1911  | 
     | 
     | 
    			return((int)mtuctl->ip6m_mtu);  | 
    
    
    1912  | 
     | 
     | 
    		}  | 
    
    
    1913  | 
     | 
     | 
    	}  | 
    
    
    1914  | 
     | 
     | 
    	return(0);  | 
    
    
    1915  | 
     | 
     | 
    }  | 
    
    
    1916  | 
     | 
     | 
     | 
    
    
    1917  | 
     | 
     | 
    /*  | 
    
    
    1918  | 
     | 
     | 
     * pr_icmph6 --  | 
    
    
    1919  | 
     | 
     | 
     *	Print a descriptive string about an ICMP header.  | 
    
    
    1920  | 
     | 
     | 
     */  | 
    
    
    1921  | 
     | 
     | 
    void  | 
    
    
    1922  | 
     | 
     | 
    pr_icmph6(struct icmp6_hdr *icp, u_char *end)  | 
    
    
    1923  | 
     | 
     | 
    { | 
    
    
    1924  | 
     | 
     | 
    	char ntop_buf[INET6_ADDRSTRLEN];  | 
    
    
    1925  | 
     | 
     | 
    	struct nd_redirect *red;  | 
    
    
    1926  | 
     | 
     | 
     | 
    
    
    1927  | 
     | 
     | 
    	switch (icp->icmp6_type) { | 
    
    
    1928  | 
     | 
     | 
    	case ICMP6_DST_UNREACH:  | 
    
    
    1929  | 
     | 
     | 
    		switch (icp->icmp6_code) { | 
    
    
    1930  | 
     | 
     | 
    		case ICMP6_DST_UNREACH_NOROUTE:  | 
    
    
    1931  | 
     | 
     | 
    			printf("No Route to Destination\n"); | 
    
    
    1932  | 
     | 
     | 
    			break;  | 
    
    
    1933  | 
     | 
     | 
    		case ICMP6_DST_UNREACH_ADMIN:  | 
    
    
    1934  | 
     | 
     | 
    			printf("Destination Administratively " | 
    
    
    1935  | 
     | 
     | 
    			    "Unreachable\n");  | 
    
    
    1936  | 
     | 
     | 
    			break;  | 
    
    
    1937  | 
     | 
     | 
    		case ICMP6_DST_UNREACH_BEYONDSCOPE:  | 
    
    
    1938  | 
     | 
     | 
    			printf("Destination Unreachable Beyond Scope\n"); | 
    
    
    1939  | 
     | 
     | 
    			break;  | 
    
    
    1940  | 
     | 
     | 
    		case ICMP6_DST_UNREACH_ADDR:  | 
    
    
    1941  | 
     | 
     | 
    			printf("Destination Host Unreachable\n"); | 
    
    
    1942  | 
     | 
     | 
    			break;  | 
    
    
    1943  | 
     | 
     | 
    		case ICMP6_DST_UNREACH_NOPORT:  | 
    
    
    1944  | 
     | 
     | 
    			printf("Destination Port Unreachable\n"); | 
    
    
    1945  | 
     | 
     | 
    			break;  | 
    
    
    1946  | 
     | 
     | 
    		default:  | 
    
    
    1947  | 
     | 
     | 
    			printf("Destination Unreachable, Bad Code: %d\n", | 
    
    
    1948  | 
     | 
     | 
    			    icp->icmp6_code);  | 
    
    
    1949  | 
     | 
     | 
    			break;  | 
    
    
    1950  | 
     | 
     | 
    		}  | 
    
    
    1951  | 
     | 
     | 
    		/* Print returned IP header information */  | 
    
    
    1952  | 
     | 
     | 
    		pr_retip6((struct ip6_hdr *)(icp + 1), end);  | 
    
    
    1953  | 
     | 
     | 
    		break;  | 
    
    
    1954  | 
     | 
     | 
    	case ICMP6_PACKET_TOO_BIG:  | 
    
    
    1955  | 
     | 
     | 
    		printf("Packet too big mtu = %d\n", | 
    
    
    1956  | 
     | 
     | 
    		    (int)ntohl(icp->icmp6_mtu));  | 
    
    
    1957  | 
     | 
     | 
    		pr_retip6((struct ip6_hdr *)(icp + 1), end);  | 
    
    
    1958  | 
     | 
     | 
    		break;  | 
    
    
    1959  | 
     | 
     | 
    	case ICMP6_TIME_EXCEEDED:  | 
    
    
    1960  | 
     | 
     | 
    		switch (icp->icmp6_code) { | 
    
    
    1961  | 
     | 
     | 
    		case ICMP6_TIME_EXCEED_TRANSIT:  | 
    
    
    1962  | 
     | 
     | 
    			printf("Time to live exceeded\n"); | 
    
    
    1963  | 
     | 
     | 
    			break;  | 
    
    
    1964  | 
     | 
     | 
    		case ICMP6_TIME_EXCEED_REASSEMBLY:  | 
    
    
    1965  | 
     | 
     | 
    			printf("Frag reassembly time exceeded\n"); | 
    
    
    1966  | 
     | 
     | 
    			break;  | 
    
    
    1967  | 
     | 
     | 
    		default:  | 
    
    
    1968  | 
     | 
     | 
    			printf("Time exceeded, Bad Code: %d\n", | 
    
    
    1969  | 
     | 
     | 
    			    icp->icmp6_code);  | 
    
    
    1970  | 
     | 
     | 
    			break;  | 
    
    
    1971  | 
     | 
     | 
    		}  | 
    
    
    1972  | 
     | 
     | 
    		pr_retip6((struct ip6_hdr *)(icp + 1), end);  | 
    
    
    1973  | 
     | 
     | 
    		break;  | 
    
    
    1974  | 
     | 
     | 
    	case ICMP6_PARAM_PROB:  | 
    
    
    1975  | 
     | 
     | 
    		printf("Parameter problem: "); | 
    
    
    1976  | 
     | 
     | 
    		switch (icp->icmp6_code) { | 
    
    
    1977  | 
     | 
     | 
    		case ICMP6_PARAMPROB_HEADER:  | 
    
    
    1978  | 
     | 
     | 
    			printf("Erroneous Header "); | 
    
    
    1979  | 
     | 
     | 
    			break;  | 
    
    
    1980  | 
     | 
     | 
    		case ICMP6_PARAMPROB_NEXTHEADER:  | 
    
    
    1981  | 
     | 
     | 
    			printf("Unknown Nextheader "); | 
    
    
    1982  | 
     | 
     | 
    			break;  | 
    
    
    1983  | 
     | 
     | 
    		case ICMP6_PARAMPROB_OPTION:  | 
    
    
    1984  | 
     | 
     | 
    			printf("Unrecognized Option "); | 
    
    
    1985  | 
     | 
     | 
    			break;  | 
    
    
    1986  | 
     | 
     | 
    		default:  | 
    
    
    1987  | 
     | 
     | 
    			printf("Bad code(%d) ", icp->icmp6_code); | 
    
    
    1988  | 
     | 
     | 
    			break;  | 
    
    
    1989  | 
     | 
     | 
    		}  | 
    
    
    1990  | 
     | 
     | 
    		printf("pointer = 0x%02x\n", | 
    
    
    1991  | 
     | 
     | 
    		    (u_int32_t)ntohl(icp->icmp6_pptr));  | 
    
    
    1992  | 
     | 
     | 
    		pr_retip6((struct ip6_hdr *)(icp + 1), end);  | 
    
    
    1993  | 
     | 
     | 
    		break;  | 
    
    
    1994  | 
     | 
     | 
    	case ICMP6_ECHO_REQUEST:  | 
    
    
    1995  | 
     | 
     | 
    		printf("Echo Request"); | 
    
    
    1996  | 
     | 
     | 
    		/* XXX ID + Seq + Data */  | 
    
    
    1997  | 
     | 
     | 
    		break;  | 
    
    
    1998  | 
     | 
     | 
    	case ICMP6_ECHO_REPLY:  | 
    
    
    1999  | 
     | 
     | 
    		printf("Echo Reply"); | 
    
    
    2000  | 
     | 
     | 
    		/* XXX ID + Seq + Data */  | 
    
    
    2001  | 
     | 
     | 
    		break;  | 
    
    
    2002  | 
     | 
     | 
    	case ICMP6_MEMBERSHIP_QUERY:  | 
    
    
    2003  | 
     | 
     | 
    		printf("Listener Query"); | 
    
    
    2004  | 
     | 
     | 
    		break;  | 
    
    
    2005  | 
     | 
     | 
    	case ICMP6_MEMBERSHIP_REPORT:  | 
    
    
    2006  | 
     | 
     | 
    		printf("Listener Report"); | 
    
    
    2007  | 
     | 
     | 
    		break;  | 
    
    
    2008  | 
     | 
     | 
    	case ICMP6_MEMBERSHIP_REDUCTION:  | 
    
    
    2009  | 
     | 
     | 
    		printf("Listener Done"); | 
    
    
    2010  | 
     | 
     | 
    		break;  | 
    
    
    2011  | 
     | 
     | 
    	case ND_ROUTER_SOLICIT:  | 
    
    
    2012  | 
     | 
     | 
    		printf("Router Solicitation"); | 
    
    
    2013  | 
     | 
     | 
    		break;  | 
    
    
    2014  | 
     | 
     | 
    	case ND_ROUTER_ADVERT:  | 
    
    
    2015  | 
     | 
     | 
    		printf("Router Advertisement"); | 
    
    
    2016  | 
     | 
     | 
    		break;  | 
    
    
    2017  | 
     | 
     | 
    	case ND_NEIGHBOR_SOLICIT:  | 
    
    
    2018  | 
     | 
     | 
    		printf("Neighbor Solicitation"); | 
    
    
    2019  | 
     | 
     | 
    		break;  | 
    
    
    2020  | 
     | 
     | 
    	case ND_NEIGHBOR_ADVERT:  | 
    
    
    2021  | 
     | 
     | 
    		printf("Neighbor Advertisement"); | 
    
    
    2022  | 
     | 
     | 
    		break;  | 
    
    
    2023  | 
     | 
     | 
    	case ND_REDIRECT:  | 
    
    
    2024  | 
     | 
     | 
    		red = (struct nd_redirect *)icp;  | 
    
    
    2025  | 
     | 
     | 
    		printf("Redirect\n"); | 
    
    
    2026  | 
     | 
     | 
    		if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,  | 
    
    
    2027  | 
     | 
     | 
    		    sizeof(ntop_buf)))  | 
    
    
    2028  | 
     | 
     | 
    			strncpy(ntop_buf, "?", sizeof(ntop_buf));  | 
    
    
    2029  | 
     | 
     | 
    		printf("Destination: %s", ntop_buf); | 
    
    
    2030  | 
     | 
     | 
    		if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,  | 
    
    
    2031  | 
     | 
     | 
    		    sizeof(ntop_buf)))  | 
    
    
    2032  | 
     | 
     | 
    			strncpy(ntop_buf, "?", sizeof(ntop_buf));  | 
    
    
    2033  | 
     | 
     | 
    		printf(" New Target: %s", ntop_buf); | 
    
    
    2034  | 
     | 
     | 
    		break;  | 
    
    
    2035  | 
     | 
     | 
    	default:  | 
    
    
    2036  | 
     | 
     | 
    		printf("Bad ICMP type: %d", icp->icmp6_type); | 
    
    
    2037  | 
     | 
     | 
    	}  | 
    
    
    2038  | 
     | 
     | 
    }  | 
    
    
    2039  | 
     | 
     | 
     | 
    
    
    2040  | 
     | 
     | 
    /*  | 
    
    
    2041  | 
     | 
     | 
     * pr_iph6 --  | 
    
    
    2042  | 
     | 
     | 
     *	Print an IP6 header.  | 
    
    
    2043  | 
     | 
     | 
     */  | 
    
    
    2044  | 
     | 
     | 
    void  | 
    
    
    2045  | 
     | 
     | 
    pr_iph6(struct ip6_hdr *ip6)  | 
    
    
    2046  | 
     | 
     | 
    { | 
    
    
    2047  | 
     | 
     | 
    	u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;  | 
    
    
    2048  | 
     | 
     | 
    	u_int8_t tc;  | 
    
    
    2049  | 
     | 
     | 
    	char ntop_buf[INET6_ADDRSTRLEN];  | 
    
    
    2050  | 
     | 
     | 
     | 
    
    
    2051  | 
     | 
     | 
    	tc = *(&ip6->ip6_vfc + 1); /* XXX */  | 
    
    
    2052  | 
     | 
     | 
    	tc = (tc >> 4) & 0x0f;  | 
    
    
    2053  | 
     | 
     | 
    	tc |= (ip6->ip6_vfc << 4);  | 
    
    
    2054  | 
     | 
     | 
     | 
    
    
    2055  | 
     | 
     | 
    	printf("Vr TC  Flow Plen Nxt Hlim\n"); | 
    
    
    2056  | 
     | 
     | 
    	printf(" %1x %02x %05x %04x  %02x   %02x\n", | 
    
    
    2057  | 
     | 
     | 
    	    (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),  | 
    
    
    2058  | 
     | 
     | 
    	    ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);  | 
    
    
    2059  | 
     | 
     | 
    	if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))  | 
    
    
    2060  | 
     | 
     | 
    		strncpy(ntop_buf, "?", sizeof(ntop_buf));  | 
    
    
    2061  | 
     | 
     | 
    	printf("%s->", ntop_buf); | 
    
    
    2062  | 
     | 
     | 
    	if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))  | 
    
    
    2063  | 
     | 
     | 
    		strncpy(ntop_buf, "?", sizeof(ntop_buf));  | 
    
    
    2064  | 
     | 
     | 
    	printf("%s\n", ntop_buf); | 
    
    
    2065  | 
     | 
     | 
    }  | 
    
    
    2066  | 
     | 
     | 
     | 
    
    
    2067  | 
     | 
     | 
    /*  | 
    
    
    2068  | 
     | 
     | 
     * pr_retip6 --  | 
    
    
    2069  | 
     | 
     | 
     *	Dump some info on a returned (via ICMPv6) IPv6 packet.  | 
    
    
    2070  | 
     | 
     | 
     */  | 
    
    
    2071  | 
     | 
     | 
    void  | 
    
    
    2072  | 
     | 
     | 
    pr_retip6(struct ip6_hdr *ip6, u_char *end)  | 
    
    
    2073  | 
     | 
     | 
    { | 
    
    
    2074  | 
     | 
     | 
    	u_char *cp = (u_char *)ip6, nh;  | 
    
    
    2075  | 
     | 
     | 
    	int hlen;  | 
    
    
    2076  | 
     | 
     | 
     | 
    
    
    2077  | 
     | 
     | 
    	if (end - (u_char *)ip6 < sizeof(*ip6)) { | 
    
    
    2078  | 
     | 
     | 
    		printf("IP6"); | 
    
    
    2079  | 
     | 
     | 
    		goto trunc;  | 
    
    
    2080  | 
     | 
     | 
    	}  | 
    
    
    2081  | 
     | 
     | 
    	pr_iph6(ip6);  | 
    
    
    2082  | 
     | 
     | 
    	hlen = sizeof(*ip6);  | 
    
    
    2083  | 
     | 
     | 
     | 
    
    
    2084  | 
     | 
     | 
    	nh = ip6->ip6_nxt;  | 
    
    
    2085  | 
     | 
     | 
    	cp += hlen;  | 
    
    
    2086  | 
     | 
     | 
    	while (end - cp >= 8) { | 
    
    
    2087  | 
     | 
     | 
    		switch (nh) { | 
    
    
    2088  | 
     | 
     | 
    		case IPPROTO_HOPOPTS:  | 
    
    
    2089  | 
     | 
     | 
    			printf("HBH "); | 
    
    
    2090  | 
     | 
     | 
    			hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;  | 
    
    
    2091  | 
     | 
     | 
    			nh = ((struct ip6_hbh *)cp)->ip6h_nxt;  | 
    
    
    2092  | 
     | 
     | 
    			break;  | 
    
    
    2093  | 
     | 
     | 
    		case IPPROTO_DSTOPTS:  | 
    
    
    2094  | 
     | 
     | 
    			printf("DSTOPT "); | 
    
    
    2095  | 
     | 
     | 
    			hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;  | 
    
    
    2096  | 
     | 
     | 
    			nh = ((struct ip6_dest *)cp)->ip6d_nxt;  | 
    
    
    2097  | 
     | 
     | 
    			break;  | 
    
    
    2098  | 
     | 
     | 
    		case IPPROTO_FRAGMENT:  | 
    
    
    2099  | 
     | 
     | 
    			printf("FRAG "); | 
    
    
    2100  | 
     | 
     | 
    			hlen = sizeof(struct ip6_frag);  | 
    
    
    2101  | 
     | 
     | 
    			nh = ((struct ip6_frag *)cp)->ip6f_nxt;  | 
    
    
    2102  | 
     | 
     | 
    			break;  | 
    
    
    2103  | 
     | 
     | 
    		case IPPROTO_ROUTING:  | 
    
    
    2104  | 
     | 
     | 
    			printf("RTHDR "); | 
    
    
    2105  | 
     | 
     | 
    			hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;  | 
    
    
    2106  | 
     | 
     | 
    			nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;  | 
    
    
    2107  | 
     | 
     | 
    			break;  | 
    
    
    2108  | 
     | 
     | 
    		case IPPROTO_AH:  | 
    
    
    2109  | 
     | 
     | 
    			printf("AH "); | 
    
    
    2110  | 
     | 
     | 
    			hlen = (((struct ah *)cp)->ah_hl+2) << 2;  | 
    
    
    2111  | 
     | 
     | 
    			nh = ((struct ah *)cp)->ah_nh;  | 
    
    
    2112  | 
     | 
     | 
    			break;  | 
    
    
    2113  | 
     | 
     | 
    		case IPPROTO_ICMPV6:  | 
    
    
    2114  | 
     | 
     | 
    			printf("ICMP6: type = %d, code = %d\n", | 
    
    
    2115  | 
     | 
     | 
    			    *cp, *(cp + 1));  | 
    
    
    2116  | 
     | 
     | 
    			return;  | 
    
    
    2117  | 
     | 
     | 
    		case IPPROTO_ESP:  | 
    
    
    2118  | 
     | 
     | 
    			printf("ESP\n"); | 
    
    
    2119  | 
     | 
     | 
    			return;  | 
    
    
    2120  | 
     | 
     | 
    		case IPPROTO_TCP:  | 
    
    
    2121  | 
     | 
     | 
    			printf("TCP: from port %u, to port %u (decimal)\n", | 
    
    
    2122  | 
     | 
     | 
    			    (*cp * 256 + *(cp + 1)),  | 
    
    
    2123  | 
     | 
     | 
    			    (*(cp + 2) * 256 + *(cp + 3)));  | 
    
    
    2124  | 
     | 
     | 
    			return;  | 
    
    
    2125  | 
     | 
     | 
    		case IPPROTO_UDP:  | 
    
    
    2126  | 
     | 
     | 
    			printf("UDP: from port %u, to port %u (decimal)\n", | 
    
    
    2127  | 
     | 
     | 
    			    (*cp * 256 + *(cp + 1)),  | 
    
    
    2128  | 
     | 
     | 
    			    (*(cp + 2) * 256 + *(cp + 3)));  | 
    
    
    2129  | 
     | 
     | 
    			return;  | 
    
    
    2130  | 
     | 
     | 
    		default:  | 
    
    
    2131  | 
     | 
     | 
    			printf("Unknown Header(%d)\n", nh); | 
    
    
    2132  | 
     | 
     | 
    			return;  | 
    
    
    2133  | 
     | 
     | 
    		}  | 
    
    
    2134  | 
     | 
     | 
     | 
    
    
    2135  | 
     | 
     | 
    		if ((cp += hlen) >= end)  | 
    
    
    2136  | 
     | 
     | 
    			goto trunc;  | 
    
    
    2137  | 
     | 
     | 
    	}  | 
    
    
    2138  | 
     | 
     | 
    	if (end - cp < 8)  | 
    
    
    2139  | 
     | 
     | 
    		goto trunc;  | 
    
    
    2140  | 
     | 
     | 
     | 
    
    
    2141  | 
     | 
     | 
    	putchar('\n'); | 
    
    
    2142  | 
     | 
     | 
    	return;  | 
    
    
    2143  | 
     | 
     | 
     | 
    
    
    2144  | 
     | 
     | 
      trunc:  | 
    
    
    2145  | 
     | 
     | 
    	printf("...\n"); | 
    
    
    2146  | 
     | 
     | 
    	return;  | 
    
    
    2147  | 
     | 
     | 
    }  | 
    
    
    2148  | 
     | 
     | 
     | 
    
    
    2149  | 
     | 
     | 
    __dead void  | 
    
    
    2150  | 
     | 
     | 
    usage(void)  | 
    
    
    2151  | 
     | 
     | 
    { | 
    
    
    2152  | 
     | 
     | 
    	if (v6flag) { | 
    
    
    2153  | 
     | 
     | 
    		fprintf(stderr,  | 
    
    
    2154  | 
     | 
     | 
    		    "usage: ping6 [-dEefHLmnqv] [-c count] [-h hoplimit] "  | 
    
    
    2155  | 
     | 
     | 
    		    "[-I sourceaddr]\n\t[-i wait] [-l preload] [-p pattern] "  | 
    
    
    2156  | 
     | 
     | 
    		    "[-s packetsize] [-V rtable]\n\t[-w maxwait] host\n");  | 
    
    
    2157  | 
     | 
     | 
    	} else { | 
    
    
    2158  | 
     | 
     | 
    		fprintf(stderr,  | 
    
    
    2159  | 
     | 
     | 
    		    "usage: ping [-DdEefHLnqRv] [-c count] [-I ifaddr]"  | 
    
    
    2160  | 
     | 
     | 
    		    " [-i wait]\n\t[-l preload] [-p pattern] [-s packetsize]"  | 
    
    
    2161  | 
     | 
     | 
    #ifndef	SMALL  | 
    
    
    2162  | 
     | 
     | 
    		    " [-T toskeyword]"  | 
    
    
    2163  | 
     | 
     | 
    #endif	/* SMALL */  | 
    
    
    2164  | 
     | 
     | 
    		    "\n\t[-t ttl] [-V rtable] [-w maxwait] host\n");  | 
    
    
    2165  | 
     | 
     | 
    	}  | 
    
    
    2166  | 
     | 
     | 
    	exit(1);  | 
    
    
    2167  | 
     | 
     | 
    }  |