📄 ping.c
字号:
/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Muuss. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */char copyright[] = "@(#) Copyright (c) 1989 The Regents of the University of California.\n" "All rights reserved.\n";/* * From: @(#)ping.c 5.9 (Berkeley) 5/12/91 */char rcsid[] = "$Id: ping.c,v 1.39 2000/07/23 04:16:21 dholland Exp $";#include "../version.h"/* * P I N G . C * * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, * measure round-trip-delays and packet loss across network paths. * * Author - * Mike Muuss * U. S. Army Ballistic Research Laboratory * December, 1983 * * Status - * Public Domain. Distribution Unlimited. * Bugs - * More statistics could always be gathered. * This program has to run SUID to ROOT to access the ICMP socket. */#include <sys/param.h>#include <sys/socket.h>#include <sys/file.h>#include <sys/time.h>#include <sys/signal.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <ctype.h>#include <errno.h>/* * Note: on some systems dropping root makes the process dumpable or * traceable. In that case if you enable dropping root and someone * traces ping, they get control of a raw socket and can start * spoofing whatever packets they like. SO BE CAREFUL. */#ifdef __linux__#define SAFE_TO_DROP_ROOT#endif/********************* Garble for libc5 ********************/#if !defined(__GLIBC__) || (__GLIBC__ < 2)#ifdef __linux__/* * The Linux kernel definitions of icmp and ip header structures are * different from traditional BSD. Linux libcs prior to libc6 don't * provide the BSD versions. Get them from the included file. */#include "pingpack.h"#endif /* __linux__ */#endif /* __GLIBC__ *//********************* Defs. *********************//* default data length: 64 byte icmp packet */#define DEFDATALEN (64 - ICMP_MINLEN)/* maximum length of IP header (including options) */#define MAXIPLEN 60/* max packet contents size */#define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - ICMP_MINLEN)/* max seconds to wait for response */#define MAXWAIT 10/* number of record route slots */#define NROUTES 9/* various options */static 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/* multicast options */static int moptions;#define MULTICAST_NOLOOP 0x001#define MULTICAST_TTL 0x002#define MULTICAST_IF 0x004/* * bitarray for remembering duplicates * * 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. Change 128 * to 8192 for complete accuracy... */#define MAX_DUP_CHK (8 * 128)static int mx_dup_ck = MAX_DUP_CHK;static char rcvd_tbl[MAX_DUP_CHK / 8];#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */#define SET(bit) (A(bit) |= B(bit))#define CLR(bit) (A(bit) &= (~B(bit)))#define TST(bit) (A(bit) & B(bit))/* characters written for flood */static const char BSPACE = '\b';static const char DOT = '.';/* transmission */static int sock; /* socket file descriptor */static int ident; /* process id to identify our packets *//* destination */static struct sockaddr_in whereto; /* who to ping */static const char *hostname;/* * input buffer * * inpack contains: * ip header (20 octets) * ip options (0-40 octets (ipoptlen)) * icmp header (8 octets) * timeval (8 or 12 octets, only if timing==1) * other data */static u_int8_t inpack[IP_MAXPACKET];static int ipoptlen;#define INPACK_IP ((struct ip *)inpack)#define INPACK_OPTS (inpack+sizeof(struct ip))#define INPACK_ICMP ((struct icmp *)(inpack+sizeof(struct ip)+ipoptlen))#define INPACK_PAYLOAD (INPACK_ICMP->icmp_data)#define INPACK_TIME ((struct timeval *)INPACK_PAYLOAD)#define INPACK_DATA (INPACK_PAYLOAD+(timing ? sizeof(struct timeval) : 0))/* * output buffer * * outpack contains: * icmp header (8 octets) * timeval (8 or 12 octets, only if timing==1) * other data * * datalen is the length of the other data plus the timeval. * note: due to alignment problems don't assign to OUTPACK_TIME, use memcpy. */static u_int8_t outpack[IP_MAXPACKET];static int datalen = DEFDATALEN;#define OUTPACK_ICMP ((struct icmp *)outpack)#define OUTPACK_PAYLOAD (OUTPACK_ICMP->icmp_data)#define OUTPACK_TIME ((struct timeval *)OUTPACK_PAYLOAD)#define OUTPACK_DATA (OUTPACK_PAYLOAD+(timing ? sizeof(struct timeval) : 0))/* counters */static long npackets; /* max packets to transmit */static long nreceived; /* # of packets we got back */static long nrepeats; /* number of duplicates */static long ntransmitted; /* sequence # for outbound packets = #sent */static int intervalsecs = 1; /* interval between packets (seconds) *//* timing */static int timing; /* flag to do timing */static long tmin = LONG_MAX; /* minimum round trip time */static long tmax = 0; /* maximum round trip time */static u_long tsum; /* sum of all times, for doing average *//********************* utility code ********************//* * in_cksum * * Checksum routine for Internet Protocol family headers (C version) */static u_int16_tin_cksum(u_int16_t *addr, int len){ int nleft = len; u_int16_t *w = addr; u_int32_t sum = 0; u_int16_t answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { answer=0; *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return(answer);}/* * tvsub * * Subtract 2 timeval structs: out = out - in. */staticvoidtvsub(struct timeval *out, const struct timeval *in){ if ((out->tv_usec -= in->tv_usec) < 0) { out->tv_sec--; out->tv_usec += 1000000; } out->tv_sec -= in->tv_sec; /* * Just in case, clamp to 0. */ if (out->tv_sec<0) { out->tv_sec = 0; out->tv_usec = 0; }}/* * tvadd * * Add 2 timeval structs: out = out + in. */staticvoidtvadd(struct timeval *out, const struct timeval *in){ if ((out->tv_usec += in->tv_usec) >= 1000000) { out->tv_sec++; out->tv_usec -= 1000000; } out->tv_sec += in->tv_sec;}/********************* printing code ********************//* * pr_addr -- * Return an ascii host address as a dotted quad and optionally with * a hostname. */static const char *pr_addr(u_int32_t l){ struct hostent *hp; static char buf[256]; struct in_addr addr; if (l==0) { return "0.0.0.0"; } addr.s_addr = l; if ((options & F_NUMERIC)==0) { hp = gethostbyaddr((char *)&l, 4, AF_INET); if (hp) { snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, inet_ntoa(addr)); return buf; } } return inet_ntoa(addr);}/* * pr_iph -- * Print an IP header with options. */staticvoidpr_iph(struct ip *ip){ u_int hlen; u_char *cp; hlen = ip->ip_hl << 2; cp = ((u_char *)ip) + sizeof(struct ip); /* point to options */ printf("Vr HL TOS Len ID Flg off TTL Pro cks " "Src Dst Data\n"); printf(" %1x %1x %02x %04x %04x", ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id); printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13, (ip->ip_off) & 0x1fff); printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); printf(" %s ", inet_ntoa(ip->ip_src)); printf(" %s ", inet_ntoa(ip->ip_dst)); /* dump any option bytes */ while (hlen-- > sizeof(struct ip)) { printf("%02x", *cp++); } putchar('\n');}/* * pr_retip -- * Dump some info on a returned (via ICMP) IP packet. */static voidpr_retip(struct ip *ip){ int hlen; u_char *cp; pr_iph(ip); hlen = ip->ip_hl << 2; /* * theoretically, ip->ip_hl is a 4-bit unsigned value, so * 0 <= hlen < 64 and cp cannot point outside inpack. */ cp = (u_char *)ip + hlen; if (ip->ip_p == 6) { printf("TCP: from port %u, to port %u (decimal)\n", (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); } else if (ip->ip_p == 17) { printf("UDP: from port %u, to port %u (decimal)\n", (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); }}/* * pr_icmph -- * Print a descriptive string about an ICMP header. */static voidpr_icmph(struct icmp *icp){ switch(icp->icmp_type) { case ICMP_ECHOREPLY: /* This is not used - we only call this for non-replies. */ printf("Echo Reply (!?)\n"); break; case ICMP_DEST_UNREACH: switch(icp->icmp_code) { case ICMP_NET_UNREACH: printf("Destination Net Unreachable\n"); break; case ICMP_HOST_UNREACH: printf("Destination Host Unreachable\n"); break; case ICMP_PROT_UNREACH: printf("Destination Protocol Unreachable\n"); break; case ICMP_PORT_UNREACH: printf("Destination Port Unreachable\n"); break; case ICMP_FRAG_NEEDED: printf("frag needed and DF set\n"); break; case ICMP_SR_FAILED: printf("Source Route Failed\n"); break; case ICMP_NET_UNKNOWN: printf("Network Unknown\n"); break; case ICMP_HOST_UNKNOWN: printf("Host Unknown\n"); break; case ICMP_HOST_ISOLATED: printf("Host Isolated\n"); break; case ICMP_NET_UNR_TOS: printf("Destination Network Unreachable at this TOS\n"); break; case ICMP_HOST_UNR_TOS: printf("Destination Host Unreachable at this TOS\n"); break;#ifdef ICMP_PKT_FILTERED case ICMP_PKT_FILTERED: printf("Packet Filtered\n"); break;#endif#ifdef ICMP_PREC_VIOLATION case ICMP_PREC_VIOLATION: printf("Precedence Violation\n"); break;#endif#ifdef ICMP_PREC_CUTOFF case ICMP_PREC_CUTOFF: printf("Precedence Cutoff\n"); break;#endif default: printf("Dest Unreachable, Unknown Code: %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -