1313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
2313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Copyright (c) 1989 The Regents of the University of California.
3313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * All rights reserved.
4313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
5313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * This code is derived from software contributed to Berkeley by
6313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Mike Muuss.
7313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
8313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Redistribution and use in source and binary forms, with or without
9313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * modification, are permitted provided that the following conditions
10313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * are met:
11313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 1. Redistributions of source code must retain the above copyright
12313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *    notice, this list of conditions and the following disclaimer.
13313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 2. Redistributions in binary form must reproduce the above copyright
14313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *    notice, this list of conditions and the following disclaimer in the
15313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *    documentation and/or other materials provided with the distribution.
16313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 3. All advertising materials mentioning features or use of this software
17313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *    must display the following acknowledgement:
18313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	This product includes software developed by the University of
19313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	California, Berkeley and its contributors.
20313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 4. Neither the name of the University nor the names of its contributors
21313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *    may be used to endorse or promote products derived from this software
22313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *    without specific prior written permission.
23313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
24313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * SUCH DAMAGE.
35313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
36313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
37313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef lint
38313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar copyright[] =
39313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
40313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti All rights reserved.\n";
41313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif /* not lint */
42313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
43313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
44313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *			P I N G . C
45313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
46313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
47313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * measure round-trip-delays and packet loss across network paths.
48313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
49313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Author -
50313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	Mike Muuss
51313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	U. S. Army Ballistic Research Laboratory
52313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	December, 1983
53313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *
54313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Status -
55313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	Public Domain.  Distribution Unlimited.
56313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Bugs -
57313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	More statistics could always be gathered.
58313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	This program has to run SUID to ROOT to access the ICMP socket.
59313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
60313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
61313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include "ping_common.h"
62313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
63313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <netinet/ip.h>
64313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <netinet/ip_icmp.h>
65313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef WITHOUT_IFADDRS
66313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <ifaddrs.h>
67313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
68313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
69313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef ICMP_FILTER
70313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define ICMP_FILTER	1
71313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct icmp_filter {
72313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	__u32	data;
73313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti};
74313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
75313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
76313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define	MAXIPLEN	60
77313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define	MAXICMPLEN	76
78313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define	NROUTES		9		/* number of record route slots */
79313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define TOS_MAX		255		/* 8-bit TOS field */
80313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define MAX_HOSTNAMELEN	NI_MAXHOST
81313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
82313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
83313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic int ts_type;
84313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic int nroute = 0;
85313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic __u32 route[10];
86313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
87313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
88313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
89313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct sockaddr_in whereto;	/* who to ping */
90313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint optlen = 0;
91313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint settos = 0;			/* Set TOS, Precendence or other QOS options */
92313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint icmp_sock;			/* socket file descriptor */
93313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiu_char outpack[0x10000];
94313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint maxpacket = sizeof(outpack);
95313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
96313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic int broadcast_pings = 0;
97313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
98313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic char *pr_addr(__u32);
99313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic void pr_options(unsigned char * cp, int hlen);
100313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic void pr_iph(struct iphdr *ip);
101313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic void usage(void) __attribute__((noreturn));
102313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic u_short in_cksum(const u_short *addr, int len, u_short salt);
103313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp);
104313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic int parsetos(char *str);
105313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
106313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistatic struct {
107313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct cmsghdr cm;
108313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct in_pktinfo ipi;
109313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} cmsg = { {sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO},
110313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	   {0, }};
111313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint cmsg_len;
112313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
113313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct sockaddr_in source;
114313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar *device;
115313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint pmtudisc = -1;
116313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
117eadaaeadfa3d5fcf49f433896e9244f0a10a5f63Lorenzo Colitti
118313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint
119313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittimain(int argc, char **argv)
120313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
121313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct hostent *hp;
122313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int ch, hold, packlen;
1237618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti	int socket_errno = 0;
124313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	u_char *packet;
125313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char *target;
126313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
127313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char *hnamebuf = NULL;
128313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#else
129313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char hnamebuf[MAX_HOSTNAMELEN];
130313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
131313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char rspace[3 + 4 * NROUTES + 1];	/* record route space */
132313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1335df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti#ifdef ANDROID
134924a10d5d9645d4e82fa4b9781f2d85b41ec74f1Lorenzo Colitti	android_check_security();
1355df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti#endif
1365df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti
137313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	limit_capabilities();
138313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
139313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
140313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	setlocale(LC_ALL, "");
141313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
142313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1435df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	icmp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
1447618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti	if (icmp_sock < 0) {
1457618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti		enable_capability_raw();
1465df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1477618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti		socket_errno = errno;
1487618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti		disable_capability_raw();
1497618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti		using_ping_socket = 0;
1507618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti	}
151313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
152313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	source.sin_family = AF_INET;
153313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
154313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	preload = 1;
155313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	while ((ch = getopt(argc, argv, COMMON_OPTSTR "bRT:")) != EOF) {
156313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch(ch) {
157313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'b':
158313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			broadcast_pings = 1;
159313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
160313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'Q':
161313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			settos = parsetos(optarg);
162313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (settos &&
163313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			    (setsockopt(icmp_sock, IPPROTO_IP, IP_TOS,
164313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					(char *)&settos, sizeof(int)) < 0)) {
165313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				perror("ping: error setting QOS sockopts");
166313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
167313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
168313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
169313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'R':
170313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (options & F_TIMESTAMP) {
171313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "Only one of -T or -R may be used\n");
172313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
173313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
174313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			options |= F_RROUTE;
175313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
176313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'T':
177313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (options & F_RROUTE) {
178313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "Only one of -T or -R may be used\n");
179313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
180313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
181313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			options |= F_TIMESTAMP;
182313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (strcmp(optarg, "tsonly") == 0)
183313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ts_type = IPOPT_TS_TSONLY;
184313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else if (strcmp(optarg, "tsandaddr") == 0)
185313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ts_type = IPOPT_TS_TSANDADDR;
186313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else if (strcmp(optarg, "tsprespec") == 0)
187313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ts_type = IPOPT_TS_PRESPEC;
188313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else {
189313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "Invalid timestamp type\n");
190313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
191313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
192313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
193313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'I':
194313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		{
195313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#if 0
196313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			char dummy;
197313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int i1, i2, i3, i4;
198313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
199313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (sscanf(optarg, "%u.%u.%u.%u%c",
200313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				   &i1, &i2, &i3, &i4, &dummy) == 4) {
201313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				__u8 *ptr;
202313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ptr = (__u8*)&source.sin_addr;
203313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ptr[0] = i1;
204313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ptr[1] = i2;
205313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ptr[2] = i3;
206313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				ptr[3] = i4;
207313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				options |= F_STRICTSOURCE;
208313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			} else {
209313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				device = optarg;
210313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
211313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#else
212313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (inet_pton(AF_INET, optarg, &source.sin_addr) > 0)
213313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				options |= F_STRICTSOURCE;
214313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else
215313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				device = optarg;
216313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
217313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
218313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
219313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'M':
220313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (strcmp(optarg, "do") == 0)
221313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				pmtudisc = IP_PMTUDISC_DO;
222313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else if (strcmp(optarg, "dont") == 0)
223313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				pmtudisc = IP_PMTUDISC_DONT;
224313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else if (strcmp(optarg, "want") == 0)
225313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				pmtudisc = IP_PMTUDISC_WANT;
226313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else {
227313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n");
228313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
229313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
230313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
231313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case 'V':
232313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("ping utility, iputils-%s\n", SNAPSHOT);
233313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(0);
234313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		COMMON_OPTIONS
235313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			common_options(ch);
236313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
237313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
238313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			usage();
239313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
240313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
241313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	argc -= optind;
242313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	argv += optind;
243313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
244313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (argc == 0)
245313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		usage();
246313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (argc > 1) {
247313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_RROUTE)
248313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			usage();
249313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		else if (options & F_TIMESTAMP) {
250313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (ts_type != IPOPT_TS_PRESPEC)
251313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				usage();
252313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (argc > 5)
253313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				usage();
254313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		} else {
255313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (argc > 10)
256313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				usage();
257313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			options |= F_SOURCEROUTE;
258313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
259313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
260313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	while (argc > 0) {
261313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		target = *argv;
262313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
263313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		memset((char *)&whereto, 0, sizeof(whereto));
264313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		whereto.sin_family = AF_INET;
265313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (inet_aton(target, &whereto.sin_addr) == 1) {
266313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			hostname = target;
267313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (argc == 1)
268313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				options |= F_NUMERIC;
269313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		} else {
270313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			char *idn;
271313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
272313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int rc;
273313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
274313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (hnamebuf) {
275313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				free(hnamebuf);
276313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				hnamebuf = NULL;
277313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
278313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
279313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			rc = idna_to_ascii_lz(target, &idn, 0);
280313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (rc != IDNA_SUCCESS) {
281313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "ping: IDN encoding failed: %s\n", idna_strerror(rc));
282313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
283313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
284313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#else
285313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			idn = target;
286313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
287313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			hp = gethostbyname(idn);
288313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (!hp) {
289313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "ping: unknown host %s\n", target);
290313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
291313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
292313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
293313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			free(idn);
294313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
295313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			memcpy(&whereto.sin_addr, hp->h_addr, 4);
296313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef USE_IDN
297313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (idna_to_unicode_lzlz(hp->h_name, &hnamebuf, 0) != IDNA_SUCCESS) {
298313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				hnamebuf = strdup(hp->h_name);
299313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (!hnamebuf) {
300313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					perror("ping: strdup");
301313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					exit(-1);
302313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
303313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
304313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#else
305313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
306313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			hnamebuf[sizeof(hnamebuf) - 1] = 0;
307313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
308313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			hostname = hnamebuf;
309313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
310313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (argc > 1)
311313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			route[nroute++] = whereto.sin_addr.s_addr;
312313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		argc--;
313313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		argv++;
314313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
315313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
316313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (source.sin_addr.s_addr == 0) {
317313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		socklen_t alen;
318313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct sockaddr_in dst = whereto;
319313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
320313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
321313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (probe_fd < 0) {
322313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("socket");
323313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
324313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
325313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (device) {
326313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			struct ifreq ifr;
327313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int rc;
328313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
329313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			memset(&ifr, 0, sizeof(ifr));
330313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
331313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
332313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			enable_capability_raw();
333313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			rc = setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1);
334313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			disable_capability_raw();
335313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
336313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (rc == -1) {
337313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
338313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					struct ip_mreqn imr;
339313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) {
340313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						fprintf(stderr, "ping: unknown iface %s\n", device);
341313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						exit(2);
342313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					}
343313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					memset(&imr, 0, sizeof(imr));
344313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					imr.imr_ifindex = ifr.ifr_ifindex;
345313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (setsockopt(probe_fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) {
346313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						perror("ping: IP_MULTICAST_IF");
347313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						exit(2);
348313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					}
349313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				} else {
350313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					perror("ping: SO_BINDTODEVICE");
351313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					exit(2);
352313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
353313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
354313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
355313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
356313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (settos &&
357313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		    setsockopt(probe_fd, IPPROTO_IP, IP_TOS, (char *)&settos, sizeof(int)) < 0)
358313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("Warning: error setting QOS sockopts");
359313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
360313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		dst.sin_port = htons(1025);
361313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (nroute)
362313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			dst.sin_addr.s_addr = route[0];
3633d667ccb6c8aa805006cfbe2bc793a4ee1ae0047Lorenzo Colitti
3643d667ccb6c8aa805006cfbe2bc793a4ee1ae0047Lorenzo Colitti		sock_setmark(probe_fd);
3653d667ccb6c8aa805006cfbe2bc793a4ee1ae0047Lorenzo Colitti
366313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
367313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (errno == EACCES) {
368313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (broadcast_pings == 0) {
369313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					fprintf(stderr, "Do you want to ping broadcast? Then -b\n");
370313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					exit(2);
371313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
372313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "WARNING: pinging broadcast address\n");
373313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (setsockopt(probe_fd, SOL_SOCKET, SO_BROADCAST,
374313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					       &broadcast_pings, sizeof(broadcast_pings)) < 0) {
375313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					perror ("can't set broadcasting");
376313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					exit(2);
377313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
378313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
379313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					perror("connect");
380313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					exit(2);
381313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
382313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			} else {
383313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				perror("connect");
384313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
385313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
386313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
387313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		alen = sizeof(source);
388313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) {
389313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("getsockname");
390313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
391313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
392313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		source.sin_port = 0;
393313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
394313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef WITHOUT_IFADDRS
395313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (device) {
396313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			struct ifaddrs *ifa0, *ifa;
397313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int ret;
398313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
399313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			ret = getifaddrs(&ifa0);
400313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (ret) {
401313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "gatifaddrs() failed.\n");
402313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
403313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
404313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
405313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
406313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					continue;
407313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (!strncmp(ifa->ifa_name, device, sizeof(device) - 1) &&
408313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				    !memcmp(&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
409313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					    &source.sin_addr, sizeof(source.sin_addr)))
410313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					break;
411313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
412313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			freeifaddrs(ifa0);
413313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (!ifa)
414313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "ping: Warning: source address might be selected on device other than %s.\n", device);
415313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
416313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
417313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		close(probe_fd);
418313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} while (0);
419313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
420313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (whereto.sin_addr.s_addr == 0)
421313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		whereto.sin_addr.s_addr = source.sin_addr.s_addr;
422313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
423313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (icmp_sock < 0) {
424313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		errno = socket_errno;
425313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("ping: icmp open socket");
426313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(2);
427313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
428313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
429313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (device) {
430313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct ifreq ifr;
431313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
432313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		memset(&ifr, 0, sizeof(ifr));
433313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
434313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (ioctl(icmp_sock, SIOCGIFINDEX, &ifr) < 0) {
435313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			fprintf(stderr, "ping: unknown iface %s\n", device);
436313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
437313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
438313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex;
439313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		cmsg_len = sizeof(cmsg);
440313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
441313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
442313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (broadcast_pings || IN_MULTICAST(ntohl(whereto.sin_addr.s_addr))) {
443313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (uid) {
444313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (interval < 1000) {
445313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "ping: broadcast ping with too short interval.\n");
446313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
447313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
448313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (pmtudisc >= 0 && pmtudisc != IP_PMTUDISC_DO) {
449313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				fprintf(stderr, "ping: broadcast ping does not fragment.\n");
450313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
451313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
452313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
453313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (pmtudisc < 0)
454313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pmtudisc = IP_PMTUDISC_DO;
455313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
456313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
457313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (pmtudisc >= 0) {
458313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, SOL_IP, IP_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) {
459313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("ping: IP_MTU_DISCOVER");
460313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
461313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
462313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
463313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
4647618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti	if ((options&F_STRICTSOURCE) &&
4657618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti	    bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {
4667618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti		perror("bind");
4677618e8104cac3bcc0ba509f4ba40644b665a3ac1Lorenzo Colitti		exit(2);
468313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
469313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
4705df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	if (!using_ping_socket) {
471313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct icmp_filter filt;
472313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
473313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			      (1<<ICMP_DEST_UNREACH)|
474313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			      (1<<ICMP_TIME_EXCEEDED)|
475313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			      (1<<ICMP_PARAMETERPROB)|
476313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			      (1<<ICMP_REDIRECT)|
477313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			      (1<<ICMP_ECHOREPLY));
478313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
479313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("WARNING: setsockopt(ICMP_FILTER)");
480313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
481313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
482313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	hold = 1;
483313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (setsockopt(icmp_sock, SOL_IP, IP_RECVERR, (char *)&hold, sizeof(hold)))
484313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n");
4855df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	if (using_ping_socket) {
4865df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		if (setsockopt(icmp_sock, SOL_IP, IP_RECVTTL, (char *)&hold, sizeof(hold)))
4875df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			perror("WARNING: setsockopt(IP_RECVTTL)");
4885df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		if (setsockopt(icmp_sock, SOL_IP, IP_RETOPTS, (char *)&hold, sizeof(hold)))
4895df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			perror("WARNING: setsockopt(IP_RETOPTS)");
4905df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	}
491313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
492313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* record route option */
493313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (options & F_RROUTE) {
494313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		memset(rspace, 0, sizeof(rspace));
495313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[0] = IPOPT_NOP;
496313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1+IPOPT_OPTVAL] = IPOPT_RR;
497313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1+IPOPT_OLEN] = sizeof(rspace)-1;
498313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
499313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		optlen = 40;
500313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) {
501313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("ping: record route");
502313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
503313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
504313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
505313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (options & F_TIMESTAMP) {
506313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		memset(rspace, 0, sizeof(rspace));
507313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[0] = IPOPT_TIMESTAMP;
508313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1] = (ts_type==IPOPT_TS_TSONLY ? 40 : 36);
509313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[2] = 5;
510313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[3] = ts_type;
511313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (ts_type == IPOPT_TS_PRESPEC) {
512313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int i;
513313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			rspace[1] = 4+nroute*8;
514313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			for (i=0; i<nroute; i++)
515313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				*(__u32*)&rspace[4+i*8] = route[i];
516313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
517313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
518313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			rspace[3] = 2;
519313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
520313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				perror("ping: ts option");
521313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				exit(2);
522313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
523313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
524313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		optlen = 40;
525313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
526313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (options & F_SOURCEROUTE) {
527313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int i;
528313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		memset(rspace, 0, sizeof(rspace));
529313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[0] = IPOPT_NOOP;
530313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1+IPOPT_OPTVAL] = (options & F_SO_DONTROUTE) ? IPOPT_SSRR
531313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			: IPOPT_LSRR;
532313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1+IPOPT_OLEN] = 3 + nroute*4;
533313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
534313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		for (i=0; i<nroute; i++)
535313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			*(__u32*)&rspace[4+i*4] = route[i];
536313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
537313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, 4 + nroute*4) < 0) {
538313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror("ping: record route");
539313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
540313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
541313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		optlen = 40;
542313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
543313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
544313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* Estimate memory eaten by single packet. It is rough estimate.
545313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 * Actually, for small datalen's it depends on kernel side a lot. */
546313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	hold = datalen + 8;
547313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	hold += ((hold+511)/512)*(optlen + 20 + 16 + 64 + 160);
548313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	sock_setbufs(icmp_sock, hold);
549313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
550313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (broadcast_pings) {
551313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, SOL_SOCKET, SO_BROADCAST,
552313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			       &broadcast_pings, sizeof(broadcast_pings)) < 0) {
553313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror ("ping: can't set broadcasting");
554313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
555313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
556313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
557313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
558313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (options & F_NOLOOP) {
559313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int loop = 0;
560313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
561313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti							&loop, 1) == -1) {
562313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror ("ping: can't disable multicast loopback");
563313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
564313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
565313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
566313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (options & F_TTL) {
567313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		int ittl = ttl;
568313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL,
569313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti							&ttl, 1) == -1) {
570313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror ("ping: can't set multicast time-to-live");
571313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
572313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
573313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL,
574313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti							&ittl, sizeof(ittl)) == -1) {
575313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			perror ("ping: can't set unicast time-to-live");
576313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
577313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
578313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
579313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
580313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (datalen > 0xFFFF - 8 - optlen - 20) {
581313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (uid || datalen > sizeof(outpack)-8) {
582313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			fprintf(stderr, "Error: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
583313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			exit(2);
584313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
585313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* Allow small oversize to root yet. It will cause EMSGSIZE. */
586313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fprintf(stderr, "WARNING: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
587313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
588313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
589313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (datalen >= sizeof(struct timeval))	/* can we time transfer */
590313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		timing = 1;
591313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	packlen = datalen + MAXIPLEN + MAXICMPLEN;
592313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (!(packet = (u_char *)malloc((u_int)packlen))) {
593313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fprintf(stderr, "ping: out of memory.\n");
594313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(2);
595313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
596313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
597313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("PING %s (%s) ", hostname, inet_ntoa(whereto.sin_addr));
598313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (device || (options&F_STRICTSOURCE))
599313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("from %s %s: ", inet_ntoa(source.sin_addr), device ?: "");
600313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("%d(%d) bytes of data.\n", datalen, datalen+8+optlen+20);
601313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
602313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	setup(icmp_sock);
603313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
604313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	main_loop(icmp_sock, packet, packlen);
605313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
606313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
607313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
608313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint receive_error_msg()
609313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
610313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int res;
611313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char cbuf[512];
612313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct iovec  iov;
613313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct msghdr msg;
614313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct cmsghdr *cmsg;
615313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct sock_extended_err *e;
616313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct icmphdr icmph;
617313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct sockaddr_in target;
618313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int net_errors = 0;
619313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int local_errors = 0;
620313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int saved_errno = errno;
621313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
622313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	iov.iov_base = &icmph;
623313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	iov.iov_len = sizeof(icmph);
624313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_name = (void*)&target;
625313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_namelen = sizeof(target);
626313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_iov = &iov;
627313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_iovlen = 1;
628313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_flags = 0;
629313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_control = cbuf;
630313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	msg.msg_controllen = sizeof(cbuf);
631313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
632313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
633313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (res < 0)
634313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		goto out;
635313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
636313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	e = NULL;
637313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
638313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (cmsg->cmsg_level == SOL_IP) {
639313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (cmsg->cmsg_type == IP_RECVERR)
640313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				e = (struct sock_extended_err *)CMSG_DATA(cmsg);
641313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
642313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
643313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (e == NULL)
644313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		abort();
645313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
646313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
647313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		local_errors++;
648313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_QUIET)
649313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			goto out;
650313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_FLOOD)
651313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			write_stdout("E", 1);
652313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		else if (e->ee_errno != EMSGSIZE)
653313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno));
654313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		else
655313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info);
656313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		nerrors++;
657313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
658313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
6595df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		int error_pkt;
660313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
661313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (res < sizeof(icmph) ||
662313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		    target.sin_addr.s_addr != whereto.sin_addr.s_addr ||
663313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		    icmph.type != ICMP_ECHO ||
664ce2d2d04ca21aedab67bd41dd9f89063454ed463Lorenzo Colitti		    !is_ours(icmph.un.echo.id)) {
665313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			/* Not our error, not an error at all. Clear. */
666313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			saved_errno = 0;
667313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			goto out;
668313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
669313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
6705df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		error_pkt = (e->ee_type != ICMP_REDIRECT &&
6715df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			     e->ee_type != ICMP_SOURCE_QUENCH);
6725df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		if (error_pkt) {
6735df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			acknowledge(ntohs(icmph.un.echo.sequence));
6745df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			net_errors++;
6755df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			nerrors++;
6765df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		}
6775df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		else {
6785df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			saved_errno = 0;
6795df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		}
680313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
6815df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		if (!using_ping_socket && !working_recverr) {
682313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			struct icmp_filter filt;
683313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			working_recverr = 1;
684313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			/* OK, it works. Add stronger filter. */
685313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
686313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				      (1<<ICMP_REDIRECT)|
687313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				      (1<<ICMP_ECHOREPLY));
688313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
689313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				perror("\rWARNING: setsockopt(ICMP_FILTER)");
690313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
691313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
692313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_QUIET)
693313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			goto out;
694313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_FLOOD) {
6955df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			if (error_pkt)
6965df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				write_stdout("\bE", 2);
697313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		} else {
698313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			print_timestamp();
6995df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			printf("From %s: icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence));
700313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL);
701313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			fflush(stdout);
702313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
703313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
704313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
705313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiout:
706313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	errno = saved_errno;
707313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return net_errors ? : -local_errors;
708313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
709313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
710313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
711313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * pinger --
712313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
713313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * will be added on by the kernel.  The ID field is our UNIX process ID,
714313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * and the sequence number is an ascending integer.  The first 8 bytes
715313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * of the data portion are used to hold a UNIX "timeval" struct in VAX
716313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * byte-order, to compute the round-trip time.
717313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
718313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint send_probe()
719313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
720313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct icmphdr *icp;
721313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int cc;
722313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int i;
723313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
724313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp = (struct icmphdr *)outpack;
725313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp->type = ICMP_ECHO;
726313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp->code = 0;
727313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp->checksum = 0;
728313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp->un.echo.sequence = htons(ntransmitted+1);
729313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp->un.echo.id = ident;			/* ID */
730313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
731313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	rcvd_clear(ntransmitted+1);
732313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
733313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (timing) {
734313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options&F_LATENCY) {
735313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			struct timeval tmp_tv;
736313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			gettimeofday(&tmp_tv, NULL);
737313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			memcpy(icp+1, &tmp_tv, sizeof(tmp_tv));
738313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		} else {
739313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			memset(icp+1, 0, sizeof(struct timeval));
740313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
741313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
742313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
743313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	cc = datalen + 8;			/* skips ICMP portion */
744313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
745313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* compute ICMP checksum here */
746313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp->checksum = in_cksum((u_short *)icp, cc, 0);
747313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
748313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (timing && !(options&F_LATENCY)) {
749313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		struct timeval tmp_tv;
750313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		gettimeofday(&tmp_tv, NULL);
751313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		memcpy(icp+1, &tmp_tv, sizeof(tmp_tv));
752313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		icp->checksum = in_cksum((u_short *)&tmp_tv, sizeof(tmp_tv), ~icp->checksum);
753313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
754313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
755313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	do {
756313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		static struct iovec iov = {outpack, 0};
757313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		static struct msghdr m = { &whereto, sizeof(whereto),
758313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						   &iov, 1, &cmsg, 0, 0 };
759313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		m.msg_controllen = cmsg_len;
760313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		iov.iov_len = cc;
761313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
762313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		i = sendmsg(icmp_sock, &m, confirm);
763313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		confirm = 0;
764313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} while (0);
765313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
766313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return (cc == i ? 0 : i);
767313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
768313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
769313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
770313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * parse_reply --
771313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	Print out the packet, if it came from us.  This logic is necessary
772313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
773313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * which arrive ('tis only fair).  This permits multiple copies of this
774313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * program to be run without having intermingled output (or statistics!).
775313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
776313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid pr_echo_reply(__u8 *_icp, int len)
777313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
778313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct icmphdr *icp = (struct icmphdr *)_icp;
779313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf(" icmp_seq=%u", ntohs(icp->un.echo.sequence));
780313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
781313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
782313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint
783313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiparse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
784313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
785313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct sockaddr_in *from = addr;
786313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	__u8 *buf = msg->msg_iov->iov_base;
787313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct icmphdr *icp;
788313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct iphdr *ip;
789313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int hlen;
790313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int csfailed;
7915df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	struct cmsghdr *cmsg;
7925df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	int ttl;
7935df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	__u8 *opts;
7945df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	int optlen;
795313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
796313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* Check the IP header */
797313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	ip = (struct iphdr *)buf;
7985df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	if (!using_ping_socket) {
7995df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		hlen = ip->ihl*4;
8005df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		if (cc < hlen + 8 || ip->ihl < 5) {
8015df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			if (options & F_VERBOSE)
8025df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc,
8035df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti					pr_addr(from->sin_addr.s_addr));
8045df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			return 1;
8055df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		}
8065df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		ttl = ip->ttl;
8075df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		opts = buf + sizeof(struct iphdr);
8085df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		optlen = hlen - sizeof(struct iphdr);
8095df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	} else {
8105df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		hlen = 0;
8115df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		ttl = 0;
8125df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		opts = buf;
8135df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		optlen = 0;
8145df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
8155df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			if (cmsg->cmsg_level != SOL_IP)
8165df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				continue;
8175df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			if (cmsg->cmsg_type == IP_TTL) {
8185df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				if (cmsg->cmsg_len < sizeof(int))
8195df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti					continue;
8205df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				ttl = *(int *) CMSG_DATA(cmsg);
8215df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			} else if (cmsg->cmsg_type == IP_RETOPTS) {
8225df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				opts = (__u8 *) CMSG_DATA(cmsg);
8235df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				optlen = cmsg->cmsg_len;
8245df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti			}
8255df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		}
826313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
827313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
828313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* Now the ICMP part */
829313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	cc -= hlen;
830313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	icp = (struct icmphdr *)(buf + hlen);
831313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	csfailed = in_cksum((u_short *)icp, cc, 0);
832313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
833313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (icp->type == ICMP_ECHOREPLY) {
834ce2d2d04ca21aedab67bd41dd9f89063454ed463Lorenzo Colitti		if (!is_ours(icp->un.echo.id))
835313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 1;			/* 'Twas not our ECHO */
836313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (gather_statistics((__u8*)icp, sizeof(*icp), cc,
837313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				      ntohs(icp->un.echo.sequence),
8385df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti				      ttl, 0, tv, pr_addr(from->sin_addr.s_addr),
839313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				      pr_echo_reply))
840313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 0;
841313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} else {
842313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* We fall here when a redirect or source quench arrived.
843313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		 * Also this branch processes icmp errors, when IP_RECVERR
844313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		 * is broken. */
845313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
846313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch (icp->type) {
847313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_ECHO:
848313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			/* MUST NOT */
849313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 1;
850313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_SOURCE_QUENCH:
851313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_REDIRECT:
852313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_DEST_UNREACH:
853313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_TIME_EXCEEDED:
854313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_PARAMETERPROB:
855313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			{
856313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				struct iphdr * iph = (struct  iphdr *)(&icp[1]);
857313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				struct icmphdr *icp1 = (struct icmphdr*)((unsigned char *)iph + iph->ihl*4);
858313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				int error_pkt;
859313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (cc < 8+sizeof(struct iphdr)+8 ||
860313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				    cc < 8+iph->ihl*4+8)
861313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					return 1;
862313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (icp1->type != ICMP_ECHO ||
863313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				    iph->daddr != whereto.sin_addr.s_addr ||
864ce2d2d04ca21aedab67bd41dd9f89063454ed463Lorenzo Colitti				    !is_ours(icp1->un.echo.id))
865313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					return 1;
866313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				error_pkt = (icp->type != ICMP_REDIRECT &&
867313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					     icp->type != ICMP_SOURCE_QUENCH);
868313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (error_pkt) {
869313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					acknowledge(ntohs(icp1->un.echo.sequence));
870313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (working_recverr) {
871313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						return 0;
872313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					} else {
873313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						static int once;
874313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						/* Sigh, IP_RECVERR for raw socket
875313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						 * was broken until 2.4.9. So, we ignore
876313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						 * the first error and warn on the second.
877313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						 */
878313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						if (once++ == 1)
879313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti							fprintf(stderr, "\rWARNING: kernel is not very fresh, upgrade is recommended.\n");
880313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						if (once == 1)
881313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti							return 0;
882313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					}
883313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
884313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				nerrors+=error_pkt;
885313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (options&F_QUIET)
886313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					return !error_pkt;
887313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (options & F_FLOOD) {
888313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (error_pkt)
889313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						write_stdout("\bE", 2);
890313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					return !error_pkt;
891313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
892313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				print_timestamp();
893313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				printf("From %s: icmp_seq=%u ",
894313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				       pr_addr(from->sin_addr.s_addr),
895313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				       ntohs(icp1->un.echo.sequence));
896313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (csfailed)
897313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					printf("(BAD CHECKSUM)");
898313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
899313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				return !error_pkt;
900313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
901313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
902313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			/* MUST NOT */
903313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
904313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
905313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if ((options & F_FLOOD) && !(options & (F_VERBOSE|F_QUIET))) {
906313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (!csfailed)
907313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				write_stdout("!E", 2);
908313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			else
909313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				write_stdout("!EC", 3);
910313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 0;
911313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
912313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (!(options & F_VERBOSE) || uid)
913313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 0;
914313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_PTIMEOFDAY) {
915313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			struct timeval recv_time;
916313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			gettimeofday(&recv_time, NULL);
917313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("%lu.%06lu ", (unsigned long)recv_time.tv_sec, (unsigned long)recv_time.tv_usec);
918313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
919313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("From %s: ", pr_addr(from->sin_addr.s_addr));
920313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (csfailed) {
921313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("(BAD CHECKSUM)\n");
922313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			return 0;
923313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
924313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
925313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return 0;
926313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
927313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
928313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (!(options & F_FLOOD)) {
9295df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		pr_options(opts, optlen + sizeof(struct iphdr));
930313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
931313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (options & F_AUDIBLE)
932313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			putchar('\a');
933313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		putchar('\n');
934313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fflush(stdout);
935313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} else {
936313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		putchar('\a');
937313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fflush(stdout);
938313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
939313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return 0;
940313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
941313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
942313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
943313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#if BYTE_ORDER == LITTLE_ENDIAN
944313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti# define ODDBYTE(v)	(v)
945313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#elif BYTE_ORDER == BIG_ENDIAN
946313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti# define ODDBYTE(v)	((u_short)(v) << 8)
947313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#else
948313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti# define ODDBYTE(v)	htons((u_short)(v) << 8)
949313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
950313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
951313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiu_short
952313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiin_cksum(const u_short *addr, register int len, u_short csum)
953313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
954313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	register int nleft = len;
955313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	const u_short *w = addr;
956313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	register u_short answer;
957313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	register int sum = csum;
958313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
959313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/*
960313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
961313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 *  we add sequential 16 bit words to it, and at the end, fold
962313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 *  back all the carry bits from the top 16 bits into the lower
963313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 *  16 bits.
964313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 */
965313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	while (nleft > 1)  {
966313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		sum += *w++;
967313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		nleft -= 2;
968313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
969313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
970313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* mop up an odd byte, if necessary */
971313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (nleft == 1)
972313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		sum += ODDBYTE(*(u_char *)w); /* le16toh() may be unavailable on old systems */
973313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
974313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/*
975313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 * add back carry outs from top 16 bits to low 16 bits
976313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	 */
977313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
978313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	sum += (sum >> 16);			/* add carry */
979313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	answer = ~sum;				/* truncate to 16 bits */
980313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return (answer);
981313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
982313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
983313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
984313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * pr_icmph --
985313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	Print a descriptive string about an ICMP header.
986313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
987313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp)
988313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
989313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	switch(type) {
990313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_ECHOREPLY:
991313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Echo Reply\n");
992313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* XXX ID + Seq + Data */
993313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
994313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_DEST_UNREACH:
995313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch(code) {
996313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_NET_UNREACH:
997313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Net Unreachable\n");
998313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
999313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_HOST_UNREACH:
1000313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Host Unreachable\n");
1001313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1002313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_PROT_UNREACH:
1003313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Protocol Unreachable\n");
1004313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1005313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_PORT_UNREACH:
1006313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Port Unreachable\n");
1007313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1008313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_FRAG_NEEDED:
1009313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Frag needed and DF set (mtu = %u)\n", info);
1010313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1011313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_SR_FAILED:
1012313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Source Route Failed\n");
1013313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1014313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_NET_UNKNOWN:
1015313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Net Unknown\n");
1016313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1017313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_HOST_UNKNOWN:
1018313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Host Unknown\n");
1019313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1020313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_HOST_ISOLATED:
1021313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Source Host Isolated\n");
1022313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1023313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_NET_ANO:
1024313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Net Prohibited\n");
1025313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1026313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_HOST_ANO:
1027313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Host Prohibited\n");
1028313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1029313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_NET_UNR_TOS:
1030313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Net Unreachable for Type of Service\n");
1031313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1032313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_HOST_UNR_TOS:
1033313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Destination Host Unreachable for Type of Service\n");
1034313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1035313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_PKT_FILTERED:
1036313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Packet filtered\n");
1037313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1038313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_PREC_VIOLATION:
1039313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Precedence Violation\n");
1040313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1041313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_PREC_CUTOFF:
1042313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Precedence Cutoff\n");
1043313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1044313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
1045313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Dest Unreachable, Bad Code: %d\n", code);
1046313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1047313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
1048313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (icp && (options & F_VERBOSE))
1049313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pr_iph((struct iphdr*)(icp + 1));
1050313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1051313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_SOURCE_QUENCH:
1052313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Source Quench\n");
1053313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (icp && (options & F_VERBOSE))
1054313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pr_iph((struct iphdr*)(icp + 1));
1055313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1056313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_REDIRECT:
1057313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch(code) {
1058313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_REDIR_NET:
1059313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Redirect Network");
1060313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1061313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_REDIR_HOST:
1062313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Redirect Host");
1063313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1064313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_REDIR_NETTOS:
1065313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Redirect Type of Service and Network");
1066313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1067313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_REDIR_HOSTTOS:
1068313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Redirect Type of Service and Host");
1069313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1070313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
1071313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Redirect, Bad Code: %d", code);
1072313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1073313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
10745df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti		printf("(New nexthop: %s)\n", pr_addr(icp ? icp->un.gateway : info));
1075313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (icp && (options & F_VERBOSE))
1076313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pr_iph((struct iphdr*)(icp + 1));
1077313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1078313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_ECHO:
1079313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Echo Request\n");
1080313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* XXX ID + Seq + Data */
1081313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1082313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_TIME_EXCEEDED:
1083313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch(code) {
1084313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_EXC_TTL:
1085313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Time to live exceeded\n");
1086313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1087313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case ICMP_EXC_FRAGTIME:
1088313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Frag reassembly time exceeded\n");
1089313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1090313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
1091313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("Time exceeded, Bad Code: %d\n", code);
1092313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1093313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
1094313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (icp && (options & F_VERBOSE))
1095313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pr_iph((struct iphdr*)(icp + 1));
1096313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1097313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_PARAMETERPROB:
1098313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Parameter problem: pointer = %u\n", icp ? (ntohl(icp->un.gateway)>>24) : info);
1099313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (icp && (options & F_VERBOSE))
1100313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			pr_iph((struct iphdr*)(icp + 1));
1101313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1102313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_TIMESTAMP:
1103313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Timestamp\n");
1104313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* XXX ID + Seq + 3 timestamps */
1105313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1106313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_TIMESTAMPREPLY:
1107313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Timestamp Reply\n");
1108313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* XXX ID + Seq + 3 timestamps */
1109313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1110313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_INFO_REQUEST:
1111313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Information Request\n");
1112313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* XXX ID + Seq */
1113313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1114313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_INFO_REPLY:
1115313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Information Reply\n");
1116313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		/* XXX ID + Seq */
1117313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1118313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef ICMP_MASKREQ
1119313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_MASKREQ:
1120313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Address Mask Request\n");
1121313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1122313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
1123313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef ICMP_MASKREPLY
1124313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	case ICMP_MASKREPLY:
1125313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Address Mask Reply\n");
1126313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		break;
1127313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
1128313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	default:
1129313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		printf("Bad ICMP type: %d\n", type);
1130313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
1131313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1132313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1133313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid pr_options(unsigned char * cp, int hlen)
1134313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
1135313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int i, j;
1136313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int optlen, totlen;
1137313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	unsigned char * optptr;
1138313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	static int old_rrlen;
1139313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	static char old_rr[MAX_IPOPTLEN];
1140313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1141313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	totlen = hlen-sizeof(struct iphdr);
1142313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	optptr = cp;
1143313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1144313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	while (totlen > 0) {
1145313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (*optptr == IPOPT_EOL)
1146313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1147313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (*optptr == IPOPT_NOP) {
1148313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			totlen--;
1149313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			optptr++;
1150313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("\nNOP");
1151313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			continue;
1152313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
1153313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		cp = optptr;
1154313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		optlen = optptr[1];
1155313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (optlen < 2 || optlen > totlen)
1156313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1157313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1158313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		switch (*cp) {
1159313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case IPOPT_SSRR:
1160313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case IPOPT_LSRR:
1161313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("\n%cSRR: ", *cp==IPOPT_SSRR ? 'S' : 'L');
1162313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			j = *++cp;
1163313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			i = *++cp;
1164313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			i -= 4;
1165313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			cp++;
1166313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (j > IPOPT_MINOFF) {
1167313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				for (;;) {
1168313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					__u32 address;
1169313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					memcpy(&address, cp, 4);
1170313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					cp += 4;
1171313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (address == 0)
1172313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t0.0.0.0");
1173313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					else
1174313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t%s", pr_addr(address));
1175313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					j -= 4;
1176313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					putchar('\n');
1177313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (j <= IPOPT_MINOFF)
1178313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						break;
1179313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
1180313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
1181313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1182313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case IPOPT_RR:
1183313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			j = *++cp;		/* get length */
1184313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			i = *++cp;		/* and pointer */
1185313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (i > j)
1186313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				i = j;
1187313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			i -= IPOPT_MINOFF;
1188313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (i <= 0)
1189313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				break;
1190313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (i == old_rrlen
1191313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			    && !memcmp(cp, old_rr, i)
1192313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			    && !(options & F_FLOOD)) {
1193313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				printf("\t(same route)");
1194313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				i = ((i + 3) / 4) * 4;
1195313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				cp += i;
1196313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				break;
1197313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
1198313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			old_rrlen = i;
1199313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			memcpy(old_rr, (char *)cp, i);
1200313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("\nRR: ");
1201313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			cp++;
1202313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			for (;;) {
1203313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				__u32 address;
1204313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				memcpy(&address, cp, 4);
1205313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				cp += 4;
1206313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (address == 0)
1207313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					printf("\t0.0.0.0");
1208313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				else
1209313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					printf("\t%s", pr_addr(address));
1210313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				i -= 4;
1211313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				putchar('\n');
1212313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (i <= 0)
1213313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					break;
1214313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
1215313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1216313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		case IPOPT_TS:
1217313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		{
1218313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			int stdtime = 0, nonstdtime = 0;
1219313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			__u8 flags;
1220313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			j = *++cp;		/* get length */
1221313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			i = *++cp;		/* and pointer */
1222313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (i > j)
1223313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				i = j;
1224313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			i -= 5;
1225313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (i <= 0)
1226313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				break;
1227313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			flags = *++cp;
1228313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("\nTS: ");
1229313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			cp++;
1230313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			for (;;) {
1231313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				long l;
1232313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1233313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if ((flags&0xF) != IPOPT_TS_TSONLY) {
1234313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					__u32 address;
1235313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					memcpy(&address, cp, 4);
1236313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					cp += 4;
1237313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (address == 0)
1238313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t0.0.0.0");
1239313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					else
1240313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t%s", pr_addr(address));
1241313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					i -= 4;
1242313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (i <= 0)
1243313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						break;
1244313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
1245313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				l = *cp++;
1246313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				l = (l<<8) + *cp++;
1247313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				l = (l<<8) + *cp++;
1248313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				l = (l<<8) + *cp++;
1249313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1250313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if  (l & 0x80000000) {
1251313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (nonstdtime==0)
1252313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t%ld absolute not-standard", l&0x7fffffff);
1253313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					else
1254313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t%ld not-standard", (l&0x7fffffff) - nonstdtime);
1255313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					nonstdtime = l&0x7fffffff;
1256313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				} else {
1257313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					if (stdtime==0)
1258313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t%ld absolute", l);
1259313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					else
1260313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti						printf("\t%ld", l - stdtime);
1261313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					stdtime = l;
1262313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				}
1263313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				i -= 4;
1264313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				putchar('\n');
1265313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				if (i <= 0)
1266313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti					break;
1267313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			}
1268313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			if (flags>>4)
1269313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti				printf("Unrecorded hops: %d\n", flags>>4);
1270313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1271313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
1272313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		default:
1273313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			printf("\nunknown option %x", *cp);
1274313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			break;
1275313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		}
1276313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		totlen -= optlen;
1277313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		optptr += optlen;
1278313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
1279313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1280313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1281313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1282313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
1283313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * pr_iph --
1284313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	Print an IP header with options.
1285313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
1286313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid pr_iph(struct iphdr *ip)
1287313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
1288313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int hlen;
1289313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	u_char *cp;
1290313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1291313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	hlen = ip->ihl << 2;
1292313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	cp = (u_char *)ip + 20;		/* point to options */
1293313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1294313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
1295313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf(" %1x  %1x  %02x %04x %04x",
1296313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	       ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id);
1297313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("   %1x %04x", ((ip->frag_off) & 0xe000) >> 13,
1298313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	       (ip->frag_off) & 0x1fff);
1299313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("  %02x  %02x %04x", ip->ttl, ip->protocol, ip->check);
1300313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->saddr));
1301313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->daddr));
1302313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	printf("\n");
1303313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	pr_options(cp, hlen);
1304313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1305313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1306313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*
1307313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * pr_addr --
1308313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *	Return an ascii host address as a dotted quad and optionally with
1309313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * a hostname.
1310313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */
1311313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar *
1312313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittipr_addr(__u32 addr)
1313313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
1314313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	struct hostent *hp;
1315313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	static char buf[4096];
1316313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1317313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	in_pr_addr = !setjmp(pr_addr_jmp);
1318313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1319313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (exiting || (options & F_NUMERIC) ||
1320313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	    !(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
1321313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
1322313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	else {
1323313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		char *s;
1324313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#if USE_IDN
1325313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		if (idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS)
1326313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			s = NULL;
1327313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#else
1328313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		s = NULL;
1329313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
1330313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		snprintf(buf, sizeof(buf), "%s (%s)", s ? s : hp->h_name,
1331313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			 inet_ntoa(*(struct in_addr *)&addr));
1332313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#if USE_IDN
1333313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		free(s);
1334313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif
1335313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
1336313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1337313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	in_pr_addr = 0;
1338313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1339313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return(buf);
1340313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1341313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1342313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1343313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* Set Type of Service (TOS) and other Quality of Service relating bits */
1344313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint parsetos(char *str)
1345313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
1346313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	const char *cp;
1347313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	int tos;
1348313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	char *ep;
1349313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1350313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* handle both hex and decimal values */
1351313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1352313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		cp = str + 2;
1353313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		tos = (int)strtol(cp, &ep, 16);
1354313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	} else
1355313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		tos = (int)strtol(str, &ep, 10);
1356313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1357313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* doesn't look like decimal or hex, eh? */
1358313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (*ep != '\0') {
1359313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fprintf(stderr, "ping: \"%s\" bad value for TOS\n", str);
1360313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(2);
1361313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
1362313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1363313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (tos > TOS_MAX) {
1364313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		fprintf(stderr, "ping: the decimal value of TOS bits must be 0-254 (or zero)\n");
1365313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		exit(2);
1366313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	}
1367313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	return(tos);
1368313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1369313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1370313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <linux/filter.h>
1371313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1372313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid install_filter(void)
1373313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
1374313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	static int once;
1375313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	static struct sock_filter insns[] = {
1376313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
1377313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_STMT(BPF_LD|BPF_H|BPF_IND, 4), /* Load icmp echo ident */
1378313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */
1379313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */
1380313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_STMT(BPF_LD|BPF_B|BPF_IND, 0), /* Load icmp type */
1381313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
1382313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_STMT(BPF_RET|BPF_K, 0xFFFFFFF), /* No. It passes. */
1383313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		BPF_STMT(BPF_RET|BPF_K, 0) /* Echo with wrong ident. Reject. */
1384313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	};
1385313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	static struct sock_fprog filter = {
1386313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		sizeof insns / sizeof(insns[0]),
1387313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		insns
1388313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	};
1389313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
13905df1daf326001b8d7d91a8b726ded17e09309952Lorenzo Colitti	if (once || using_ping_socket)
1391313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		return;
1392313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	once = 1;
1393313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1394313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	/* Patch bpflet for current identifier. */
1395313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(ident), 0, 1);
1396313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1397313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
1398313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		perror("WARNING: failed to install socket filter\n");
1399313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1400313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1401313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define USAGE_NEWLINE	"\n           "
1402313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti
1403313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid usage(void)
1404313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{
1405313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	fprintf(stderr,
1406313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		"Usage: ping"
1407313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-"
1408313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti			"aAbBdDfhLnOqrRUvV"
1409313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		"]"
1410313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-c count]"
1411313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-i interval]"
1412313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-I interface]"
1413313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		USAGE_NEWLINE
1414313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-m mark]"
1415313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-M pmtudisc_option]"
1416313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-l preload]"
1417313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-p pattern]"
1418313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-Q tos]"
1419313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		USAGE_NEWLINE
1420313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-s packetsize]"
1421313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-S sndbuf]"
1422313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-t ttl]"
1423313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-T timestamp_option]"
1424313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		USAGE_NEWLINE
1425313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-w deadline]"
1426313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [-W timeout]"
1427313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		" [hop1 ...] destination"
1428313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti		"\n"
1429313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	);
1430313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti	exit(2);
1431313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}
1432