summaryrefslogtreecommitdiff
path: root/ping.h
blob: e229117a2320f99b5943ff84cfe43a9fb410dff7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <poll.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/sockios.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/uio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <setjmp.h>
#include <netinet/icmp6.h>
#include <asm/byteorder.h>
#include <sched.h>
#include <math.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <linux/filter.h>
#include <resolv.h>

#ifdef CAPABILITIES
#include <sys/prctl.h>
#include <sys/capability.h>
#endif

#ifdef USE_IDN
#include <locale.h>
#include <idna.h>
#include <stringprep.h>
#define getaddrinfo_flags (AI_CANONNAME | AI_IDN | AI_CANONIDN)
#define getnameinfo_flags NI_IDN
#else
#define getaddrinfo_flags (AI_CANONNAME)
#define getnameinfo_flags 0
#endif

#ifndef WITHOUT_IFADDRS
#include <ifaddrs.h>
#endif

#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/types.h>
#include <linux/errqueue.h>

#include "in6_flowlabel.h"
#include "SNAPSHOT.h"

#ifndef SCOPE_DELIMITER
#define SCOPE_DELIMITER '%'
#endif

#define	DEFDATALEN	(64 - 8)	/* default data length */

#define	MAXWAIT		10		/* max seconds to wait for response */
#define MININTERVAL	10		/* Minimal interpacket gap */
#define MINUSERINTERVAL	200		/* Minimal allowed interval for non-root */

#define SCHINT(a)	(((a) <= MININTERVAL) ? MININTERVAL : (a))

/* various options */
extern int options;
#define	F_FLOOD		0x001
#define	F_INTERVAL	0x002
#define	F_NUMERIC	0x004
#define	F_PINGFILLED	0x008
#define	F_QUIET		0x010
#define	F_RROUTE	0x020
#define	F_SO_DEBUG	0x040
#define	F_SO_DONTROUTE	0x080
#define	F_VERBOSE	0x100
#define	F_TIMESTAMP	0x200
#define	F_SOURCEROUTE	0x400
#define	F_FLOOD_POLL	0x800
#define	F_LATENCY	0x1000
#define	F_AUDIBLE	0x2000
#define	F_ADAPTIVE	0x4000
#define	F_STRICTSOURCE	0x8000
#define F_NOLOOP	0x10000
#define F_TTL		0x20000
#define F_MARK		0x40000
#define F_PTIMEOFDAY	0x80000
#define F_OUTSTANDING	0x100000
#define F_FLOWINFO	0x200000
#define F_TCLASS	0x400000

/*
 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
 * number of received sequence numbers we can keep track of.
 */
#define	MAX_DUP_CHK	0x10000

#if defined(__WORDSIZE) && __WORDSIZE == 64
# define USE_BITMAP64
#endif

#ifdef USE_BITMAP64
typedef __u64	bitmap_t;
# define BITMAP_SHIFT	6
#else
typedef __u32	bitmap_t;
# define BITMAP_SHIFT	5
#endif

#if ((MAX_DUP_CHK >> (BITMAP_SHIFT + 3)) << (BITMAP_SHIFT + 3)) != MAX_DUP_CHK
# error Please MAX_DUP_CHK and/or BITMAP_SHIFT
#endif

struct rcvd_table {
	bitmap_t bitmap[MAX_DUP_CHK / (sizeof(bitmap_t) * 8)];
};

extern struct rcvd_table rcvd_tbl;

#define	A(bit)	(rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT])	/* identify word in array */
#define	B(bit)	(((bitmap_t)1) << ((bit) & ((1 << BITMAP_SHIFT) - 1)))	/* identify bit in word */

static inline void rcvd_set(__u16 seq)
{
	unsigned bit = seq % MAX_DUP_CHK;
	A(bit) |= B(bit);
}

static inline void rcvd_clear(__u16 seq)
{
	unsigned bit = seq % MAX_DUP_CHK;
	A(bit) &= ~B(bit);
}

static inline bitmap_t rcvd_test(__u16 seq)
{
	unsigned bit = seq % MAX_DUP_CHK;
	return A(bit) & B(bit);
}

extern int datalen;
extern char *hostname;
extern int uid;
extern int ident;			/* process id to identify our packets */

extern int sndbuf;
extern int ttl;

extern long npackets;			/* max packets to transmit */
extern long nreceived;			/* # of packets we got back */
extern long nrepeats;			/* number of duplicates */
extern long ntransmitted;		/* sequence # for outbound packets = #sent */
extern long nchecksum;			/* replies with bad checksum */
extern long nerrors;			/* icmp errors */
extern int interval;			/* interval between packets (msec) */
extern int preload;
extern int deadline;			/* time to die */
extern int lingertime;
extern struct timeval start_time, cur_time;
extern volatile int exiting;
extern volatile int status_snapshot;
extern int confirm;
extern int confirm_flag;
extern char *device;
extern int pmtudisc;

extern volatile int in_pr_addr;		/* pr_addr() is executing */
extern jmp_buf pr_addr_jmp;

#ifndef MSG_CONFIRM
#define MSG_CONFIRM 0
#endif


/* timing */
extern int timing;			/* flag to do timing */
extern long tmin;			/* minimum round trip time */
extern long tmax;			/* maximum round trip time */
extern long long tsum;			/* sum of all times, for doing average */
extern long long tsum2;
extern int rtt;
extern __u16 acked;
extern int pipesize;

/*
 * Write to stdout
 */
static inline void write_stdout(const char *str, size_t len)
{
	size_t o = 0;
	ssize_t cc;
	do {
		cc = write(STDOUT_FILENO, str + o, len - o);
		o += cc;
	} while (len > o || cc < 0);
}

/*
 * tvsub --
 *	Subtract 2 timeval structs:  out = out - in.  Out is assumed to
 * be >= in.
 */
static inline void tvsub(struct timeval *out, struct timeval *in)
{
	if ((out->tv_usec -= in->tv_usec) < 0) {
		--out->tv_sec;
		out->tv_usec += 1000000;
	}
	out->tv_sec -= in->tv_sec;
}

static inline void set_signal(int signo, void (*handler)(int))
{
	struct sigaction sa;

	memset(&sa, 0, sizeof(sa));

	sa.sa_handler = (void (*)(int))handler;
#ifdef SA_INTERRUPT
	sa.sa_flags = SA_INTERRUPT;
#endif
	sigaction(signo, &sa, NULL);
}

extern int __schedule_exit(int next);

static inline int schedule_exit(int next)
{
	if (npackets && ntransmitted >= npackets && !deadline)
		next = __schedule_exit(next);
	return next;
}

static inline int in_flight(void)
{
	__u16 diff = (__u16)ntransmitted - acked;
	return (diff<=0x7FFF) ? diff : ntransmitted-nreceived-nerrors;
}

static inline void acknowledge(__u16 seq)
{
	__u16 diff = (__u16)ntransmitted - seq;
	if (diff <= 0x7FFF) {
		if ((int)diff+1 > pipesize)
			pipesize = (int)diff+1;
		if ((__s16)(seq - acked) > 0 ||
		    (__u16)ntransmitted - acked > 0x7FFF)
			acked = seq;
	}
}

static inline void advance_ntransmitted(void)
{
	ntransmitted++;
	/* Invalidate acked, if 16 bit seq overflows. */
	if ((__u16)ntransmitted - acked > 0x7FFF)
		acked = (__u16)ntransmitted + 1;
}

extern void limit_capabilities(void);
static int enable_capability_raw(void);
static int disable_capability_raw(void);
static int enable_capability_admin(void);
static int disable_capability_admin(void);
#ifdef CAPABILITIES
extern int modify_capability(cap_value_t, cap_flag_value_t);
static inline int enable_capability_raw(void)		{ return modify_capability(CAP_NET_RAW,   CAP_SET);   }
static inline int disable_capability_raw(void)		{ return modify_capability(CAP_NET_RAW,   CAP_CLEAR); }
static inline int enable_capability_admin(void)		{ return modify_capability(CAP_NET_ADMIN, CAP_SET);   }
static inline int disable_capability_admin(void)	{ return modify_capability(CAP_NET_ADMIN, CAP_CLEAR); }
#else
extern int modify_capability(int);
static inline int enable_capability_raw(void)		{ return modify_capability(1); }
static inline int disable_capability_raw(void)		{ return modify_capability(0); }
static inline int enable_capability_admin(void)		{ return modify_capability(1); }
static inline int disable_capability_admin(void)	{ return modify_capability(0); }
#endif
extern void drop_capabilities(void);

typedef struct socket_st {
	int fd;
	int socktype;
	/* And this is workaround for bug in IP_RECVERR on raw sockets which is present
	 * in linux-2.2.[0-19], linux-2.4.[0-7] */
	int working_recverr;
} socket_st;

char *pr_addr(void *sa, socklen_t salen);

int is_ours(socket_st *sock, uint16_t id);

int ping4_run(int argc, char **argv, struct addrinfo *ai, socket_st *sock);
int ping4_send_probe(socket_st *, void *packet, unsigned packet_size);
int ping4_receive_error_msg(socket_st *);
int ping4_parse_reply(socket_st *, struct msghdr *msg, int len, void *addr, struct timeval *);
void ping4_install_filter(socket_st *);

typedef struct ping_func_set_st {
	int (*send_probe)(socket_st *, void *packet, unsigned packet_size);
	int (*receive_error_msg)(socket_st *sock);
	int (*parse_reply)(socket_st *, struct msghdr *msg, int len, void *addr, struct timeval *);
	void (*install_filter)(socket_st *);
} ping_func_set_st;

#define	MAXPACKET	128000		/* max packet size */
extern ping_func_set_st ping4_func_set;

extern int pinger(ping_func_set_st *fset, socket_st *sock);
extern void sock_setbufs(socket_st*, int alloc);
extern void setup(socket_st *);
extern int contains_pattern_in_payload(__u8 *ptr);
extern void main_loop(ping_func_set_st *fset, socket_st*, __u8 *buf, int buflen) __attribute__((noreturn));
extern void finish(void) __attribute__((noreturn));
extern void status(void);
extern void common_options(int ch);
extern int gather_statistics(__u8 *ptr, int icmplen,
			     int cc, __u16 seq, int hops,
			     int csfailed, struct timeval *tv, char *from,
			     void (*pr_reply)(__u8 *ptr, int cc));
extern void print_timestamp(void);
void fill(char *patp, void *packet, unsigned packet_size);

extern int mark;
extern unsigned char outpack[MAXPACKET];

/* IPv6 */

int ping6_run(int argc, char **argv, struct addrinfo *ai, socket_st *sock);
void ping6_usage(unsigned from_ping);

int ping6_send_probe(socket_st *sockets, void *packet, unsigned packet_size);
int ping6_receive_error_msg(socket_st *sockets);
int ping6_parse_reply(socket_st *, struct msghdr *msg, int len, void *addr, struct timeval *);
void ping6_install_filter(socket_st *sockets);

extern ping_func_set_st ping6_func_set;

int niquery_option_handler(const char *opt_arg);

extern __u32 tclass;
extern __u32 flowlabel;
extern struct sockaddr_in6 source6;
extern struct sockaddr_in6 whereto6;
extern struct sockaddr_in6 firsthop6;

/* IPv6 node information query */

#define NI_NONCE_SIZE			8

struct ni_hdr {
	struct icmp6_hdr		ni_u;
	__u8				ni_nonce[NI_NONCE_SIZE];
};

#define ni_type		ni_u.icmp6_type
#define ni_code		ni_u.icmp6_code
#define ni_cksum	ni_u.icmp6_cksum
#define ni_qtype	ni_u.icmp6_data16[0]
#define ni_flags	ni_u.icmp6_data16[1]

/* Types */
#ifndef ICMPV6_NI_QUERY
# define ICMPV6_NI_QUERY		139
# define ICMPV6_NI_REPLY		140
#endif

/* Query Codes */
#define NI_SUBJ_IPV6			0
#define NI_SUBJ_NAME			1
#define NI_SUBJ_IPV4			2

/* Reply Codes */
#define NI_SUCCESS			0
#define NI_REFUSED			1
#define NI_UNKNOWN			2

/* Qtypes */
#define NI_QTYPE_NOOP			0
#define NI_QTYPE_NAME			2
#define NI_QTYPE_IPV6ADDR		3
#define NI_QTYPE_IPV4ADDR		4

/* Flags */
#define NI_IPV6ADDR_F_TRUNCATE		__constant_cpu_to_be16(0x0001)
#define NI_IPV6ADDR_F_ALL		__constant_cpu_to_be16(0x0002)
#define NI_IPV6ADDR_F_COMPAT		__constant_cpu_to_be16(0x0004)
#define NI_IPV6ADDR_F_LINKLOCAL		__constant_cpu_to_be16(0x0008)
#define NI_IPV6ADDR_F_SITELOCAL		__constant_cpu_to_be16(0x0010)
#define NI_IPV6ADDR_F_GLOBAL		__constant_cpu_to_be16(0x0020)

#define NI_IPV4ADDR_F_TRUNCATE		NI_IPV6ADDR_F_TRUNCATE
#define NI_IPV4ADDR_F_ALL		NI_IPV6ADDR_F_ALL