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
|
#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_FLOWINFO 0x200
#define F_SOURCEROUTE 0x400
#define F_TCLASS 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
/*
* 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 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 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);
int hextoui(const char *str);
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
|