⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ping.c

📁 一个在UCLINUX环境下实现的PING程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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[] = "$Original-Id: ping.c,v 1.22 1997/06/08 19:39:47 dholland Exp $";char pkg[] = "netkit-base-0.10";/* *			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>#include <getopt.h>#include "resolv.h"#include "stamp.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#if defined(__GLIBC__) && (__GLIBC__ >= 2)#define icmphdr			icmp#define ICMP_DEST_UNREACH	ICMP_UNREACH#define ICMP_NET_UNREACH	ICMP_UNREACH_NET#define ICMP_HOST_UNREACH	ICMP_UNREACH_HOST#define ICMP_PORT_UNREACH	ICMP_UNREACH_PORT#define ICMP_PROT_UNREACH	ICMP_UNREACH_PROTOCOL#define ICMP_FRAG_NEEDED	ICMP_UNREACH_NEEDFRAG#define ICMP_SR_FAILED		ICMP_UNREACH_SRCFAIL#define ICMP_NET_UNKNOWN	ICMP_UNREACH_NET_UNKNOWN#define ICMP_HOST_UNKNOWN	ICMP_UNREACH_HOST_UNKNOWN#define ICMP_HOST_ISOLATED	ICMP_UNREACH_ISOLATED#define ICMP_NET_UNR_TOS	ICMP_UNREACH_TOSNET#define ICMP_HOST_UNR_TOS	ICMP_UNREACH_TOSHOST#define ICMP_SOURCE_QUENCH	ICMP_SOURCEQUENCH#define ICMP_REDIR_NET		ICMP_REDIRECT_NET#define ICMP_REDIR_HOST		ICMP_REDIRECT_HOST#define ICMP_REDIR_NETTOS	ICMP_REDIRECT_TOSNET#define ICMP_REDIR_HOSTTOS	ICMP_REDIRECT_TOSHOST#define ICMP_TIME_EXCEEDED	ICMP_TIMXCEED#define ICMP_EXC_TTL		ICMP_TIMXCEED_INTRANS#define ICMP_EXC_FRAGTIME	ICMP_TIMXCEED_REASS#define	ICMP_PARAMETERPROB	ICMP_PARAMPROB#define ICMP_TIMESTAMP		ICMP_TSTAMP#define ICMP_TIMESTAMPREPLY	ICMP_TSTAMPREPLY#define ICMP_INFO_REQUEST	ICMP_IREQ#define ICMP_INFO_REPLY		ICMP_IREQREPLY#else#define ICMP_MINLEN	28#define inet_ntoa(x) inet_ntoa(*((struct in_addr *)&(x)))#endif#define	DEFDATALEN	(64 - 8)	/* default data length */#define	MAXIPLEN	60#define	MAXICMPLEN	76#define	MAXPACKET	(2048 - 60 - 8)/* max packet size */#define	MAXWAIT		10		/* max seconds to wait for response */#define	NROUTES		9		/* number of record route slots */#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))/* various options */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 */int moptions;#define MULTICAST_NOLOOP	0x001#define MULTICAST_TTL		0x002#define MULTICAST_IF		0x004/* * 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)int mx_dup_ck = MAX_DUP_CHK;char rcvd_tbl[MAX_DUP_CHK / 8];struct sockaddr whereto;	/* who to ping */int datalen = DEFDATALEN;int s;				/* socket file descriptor */u_char outpack[MAXPACKET];char BSPACE = '\b';		/* characters written for flood */char DOT = '.';static char *hostname;static int ident;		/* process id to identify our packets *//* 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 interval = 1;	/* interval between packets *//* 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 *//* protos */static char *pr_addr(u_long);static int in_cksum(u_short *addr, int len);static void catcher(int);static void finish(int ignore);static void pinger(void);static void fill(void *bp, char *patp);static void usage(void);static void pr_pack(char *buf, int cc, struct sockaddr_in *from);static void tvsub(struct timeval *out, struct timeval *in);static void pr_icmph(struct icmphdr *icp);static void pr_retip(struct iphdr *ip);intmain(int argc, char *argv[]){	struct timeval timeout;	struct hostent *hp;	struct sockaddr_in *to;	struct protoent *proto;	struct in_addr ifaddr;	int i;	int ch, fdmask, hold, packlen, preload;	u_char *datap, *packet;	char *target, hnamebuf[MAXHOSTNAMELEN];	u_char ttl, loop;	int am_i_root;#ifdef IP_OPTIONS	char rspace[3 + 4 * NROUTES + 1];	/* record route space */#endif	static char *null = NULL;        check_version_argument;        	/*__environ = &null;*/	am_i_root = (getuid()==0);	/*	 * Pull this stuff up front so we can drop root if desired.	 */	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {		if (errno==EPERM) {			fprintf(stderr, "ping: ping must run as root\n");		}		else perror("ping: socket");		exit(2);	}#ifdef SAFE_TO_DROP_ROOT	setuid(getuid());#endif	preload = 0;	datap = &outpack[8 + sizeof(struct timeval)];	while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:v")) != EOF)		switch(ch) {		case 'c':			npackets = atoi(optarg);			if (npackets <= 0) {				(void)fprintf(stderr,				    "ping: bad number of packets to transmit.\n");				exit(2);			}			break;		case 'd':			options |= F_SO_DEBUG;			break;		case 'f':			if (!am_i_root) {				(void)fprintf(stderr,				    "ping: %s\n", strerror(EPERM));				exit(2);			}			options |= F_FLOOD;			setbuf(stdout, NULL);			break;		case 'i':		/* wait between sending packets */			interval = atoi(optarg);			if (interval <= 0) {				(void)fprintf(stderr,				    "ping: bad timing interval.\n");				exit(2);			}			options |= F_INTERVAL;			break;		case 'l':			if (!am_i_root) {				(void)fprintf(stderr,				    "ping: %s\n", strerror(EPERM));				exit(2);			}			preload = atoi(optarg);			if (preload < 0) {				(void)fprintf(stderr,				    "ping: bad preload value.\n");				exit(2);			}			break;		case 'n':			options |= F_NUMERIC;			break;		case 'p':		/* fill buffer with user pattern */			options |= F_PINGFILLED;			fill(datap, optarg);			break;		case 'q':			options |= F_QUIET;			break;		case 'R':			options |= F_RROUTE;			break;		case 'r':			options |= F_SO_DONTROUTE;			break;		case 's':		/* size of packet to send */			datalen = atoi(optarg);			if (datalen > MAXPACKET) {				(void)fprintf(stderr,				    "ping: packet size too large.\n");				exit(2);			}			if (datalen <= 0) {				(void)fprintf(stderr,				    "ping: illegal packet size.\n");				exit(2);			}			break;		case 'v':			options |= F_VERBOSE;			break;		case 'L':			moptions |= MULTICAST_NOLOOP;			loop = 0;			break;		case 't':			moptions |= MULTICAST_TTL;			i = atoi(optarg);			if (i < 0 || i > 255) {				printf("ttl %u out of range\n", i);				exit(2);			}			ttl = i;			break;		case 'I':			moptions |= MULTICAST_IF;			{				int i1, i2, i3, i4;				char junk;				if (sscanf(optarg, "%u.%u.%u.%u%c",					   &i1, &i2, &i3, &i4, &junk) != 4) {					printf("bad interface address '%s'\n",					       optarg);					exit(2);				}				ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4;				ifaddr.s_addr = htonl(ifaddr.s_addr);			}			break;		default:			usage();		}	argc -= optind;	argv += optind;		if (argc != 1)		usage();	target = *argv;	memset(&whereto, 0, sizeof(struct sockaddr));	to = (struct sockaddr_in *)&whereto;	to->sin_family = AF_INET;	if (inet_aton(target, &to->sin_addr)) {		hostname = target;	}	else {		char * addr = resolve_name(target, 0);		if (!addr) {			(void)fprintf(stderr,			    "ping: unknown host %s\n", target);			exit(2);		}		to->sin_addr.s_addr = inet_addr(addr);		hostname = target;		/*		hp = gethostbyname(target);		if (!hp) {			(void)fprintf(stderr,			    "ping: unknown host %s\n", target);			exit(2);		}		to->sin_family = hp->h_addrtype;		if (hp->h_length > (int)sizeof(to->sin_addr)) {			hp->h_length = sizeof(to->sin_addr);		}		memcpy(&to->sin_addr, hp->h_addr, hp->h_length);		(void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);		hostname = hnamebuf;		*/	}	if (options & F_FLOOD && options & F_INTERVAL) {		(void)fprintf(stderr,		    "ping: -f and -i incompatible options.\n");		exit(2);	}	if (datalen >= (int)sizeof(struct timeval)) /* can we time transfer */		timing = 1;	packlen = datalen + MAXIPLEN + MAXICMPLEN;	packet = malloc((u_int)packlen);	if (!packet) {		(void)fprintf(stderr, "ping: out of memory.\n");		exit(2);	}	if (!(options & F_PINGFILLED))		for (i = 8; i < datalen; ++i)			*datap++ = i;	ident = getpid() & 0xFFFF;	hold = 1;	if (options & F_SO_DEBUG)		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,		    sizeof(hold));	if (options & F_SO_DONTROUTE)		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,		    sizeof(hold));	/* this is necessary for broadcast pings to work */	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&hold, sizeof(hold));	/* record route option */	if (options & F_RROUTE) {#ifdef IP_OPTIONS	        memset(rspace, 0, sizeof(rspace));		rspace[IPOPT_OPTVAL] = IPOPT_RR;		rspace[IPOPT_OLEN] = sizeof(rspace)-1;		rspace[IPOPT_OFFSET] = IPOPT_MINOFF;		if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,		    sizeof(rspace)) < 0) {			perror("ping: record route");			exit(2);		}#else		(void)fprintf(stderr,		  "ping: record route not available in this implementation.\n");		exit(2);#endif /* IP_OPTIONS */	}	/*	 * When pinging the broadcast address, you can get a lot of answers.	 * Doing something so evil is useful if you are trying to stress the	 * ethernet, or just want to fill the arp cache to get some stuff for	 * /etc/ethers.	 */	hold = 48 * 1024;	(void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,	    sizeof(hold));/*#if 0*/	if (moptions & MULTICAST_NOLOOP) {		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP,							&loop, 1) == -1) {			perror ("can't disable multicast loopback");			exit(92);		}	}	if (moptions & MULTICAST_TTL) {		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,							&ttl, 1) == -1) {			perror ("can't set multicast time-to-live");			exit(93);		}	}	if (moptions & MULTICAST_IF) {		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,					&ifaddr, sizeof(ifaddr)) == -1) {			perror ("can't set multicast source interface");			exit(94);		}	}/*#endif*/	if (to->sin_family == AF_INET)		(void)printf("PING %s (%s): %d data bytes\n", hostname,		    inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),		    datalen);	else		(void)printf("PING %s: %d data bytes\n", hostname, datalen);	(void)signal(SIGINT, finish);	(void)signal(SIGALRM, catcher);	while (preload--)		/* fire off them quickies */		pinger();	if ((options & F_FLOOD) == 0)		catcher(0);		/* start things going */	for (;;) {		struct sockaddr_in from;		register int cc;		int fromlen;		if (options & F_FLOOD) {			pinger();			timeout.tv_sec = 0;			timeout.tv_usec = 10000;			fdmask = 1 << s;			if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,			    (fd_set *)NULL, &timeout) < 1)				continue;		}		fromlen = sizeof(from);		if ((cc = recvfrom(s, (char *)packet, packlen, 0,		    (struct sockaddr *)&from, &fromlen)) < 0) {			if (errno == EINTR)				continue;			perror("ping: recvfrom");			continue;		}		pr_pack((char *)packet, cc, &from);		if (npackets && nreceived >= npackets)			break;	}	finish(0);	/* NOTREACHED */	return 0;}/* * catcher -- *	This routine causes another PING to be transmitted, and then * schedules another SIGALRM for 1 second from now. *  * bug -- *	Our sense of time will slowly skew (i.e., packets will not be * launched exactly at 1-second intervals).  This does not affect the * quality of the delay and loss statistics. */static voidcatcher(int ignore){	int waittime;	(void)ignore;	pinger();	(void)signal(SIGALRM, catcher);	if (!npackets || ntransmitted < npackets)		alarm((u_int)interval);	else {		if (nreceived) {			waittime = 2 * tmax / 1000;			if (!waittime)				waittime = 1;			if (waittime > MAXWAIT)				waittime = MAXWAIT;		} else			waittime = MAXWAIT;		(void)signal(SIGALRM, finish);		(void)alarm((u_int)waittime);	}}#if !defined(__GLIBC__) || (__GLIBC__ < 2)#define icmp_type type#define icmp_code code#define icmp_cksum checksum#define icmp_id un.echo.id#define icmp_seq un.echo.sequence#define icmp_gwaddr un.gateway#endif /* __GLIBC__ */#define ip_hl ihl#define ip_v version#define ip_tos tos#define ip_len tot_len#define ip_id id#define ip_off frag_off#define ip_ttl ttl#define ip_p protocol#define ip_sum check#define ip_src saddr#define ip_dst daddr/* * pinger -- * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet * will be added on by the kernel.  The ID field is our UNIX process ID, * and the sequence number is an ascending integer.  The first 8 bytes * of the data portion are used to hold a UNIX "timeval" struct in VAX * byte-order, to compute the round-trip time. */static voidpinger(void){	register struct icmphdr *icp;	register int cc;	int i;	icp = (struct icmphdr *)outpack;	icp->icmp_type = ICMP_ECHO;	icp->icmp_code = 0;	icp->icmp_cksum = 0;	icp->icmp_seq = ntransmitted++;	icp->icmp_id = ident;			/* ID */	CLR(icp->icmp_seq % mx_dup_ck);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -