ping.c
来自「Linux socket 编程」· C语言 代码 · 共 1,192 行 · 第 1/3 页
C
1,192 行
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;
size_t 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 void
catcher(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 void
pinger(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);
if (timing)
(void)gettimeofday((struct timeval *)&outpack[8],
(struct timezone *)NULL);
cc = datalen + 8; /* skips ICMP portion */
/* compute ICMP checksum here */
icp->icmp_cksum = in_cksum((u_short *)icp, cc);
i = sendto(s, (char *)outpack, cc, 0, &whereto,
sizeof(struct sockaddr));
if (i < 0 || i != cc) {
if (i < 0)
perror("ping: sendto");
(void)printf("ping: wrote %s %d chars, ret=%d\n",
hostname, cc, i);
}
if (!(options & F_QUIET) && options & F_FLOOD)
(void)write(STDOUT_FILENO, &DOT, 1);
}
/*
* pr_pack --
* Print out the packet, if it came from us. This logic is necessary
* because ALL readers of the ICMP socket get a copy of ALL ICMP packets
* which arrive ('tis only fair). This permits multiple copies of this
* program to be run without having intermingled output (or statistics!).
*/
void
pr_pack(char *buf, int cc, struct sockaddr_in *from)
{
register struct icmphdr *icp;
register int i;
register u_char *cp,*dp;
/*#if 0*/
register u_long l;
register int j;
static int old_rrlen;
static char old_rr[MAX_IPOPTLEN];
/*#endif*/
struct iphdr *ip;
struct timeval tv, *tp;
long triptime = 0;
int hlen, dupflag;
(void)gettimeofday(&tv, (struct timezone *)NULL);
/* Check the IP header */
ip = (struct iphdr *)buf;
hlen = ip->ip_hl << 2;
if (cc < datalen + ICMP_MINLEN) {
if (options & F_VERBOSE)
(void)fprintf(stderr,
"ping: packet too short (%d bytes) from %s\n", cc,
inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
return;
}
/* Now the ICMP part */
cc -= hlen;
icp = (struct icmphdr *)(buf + hlen);
if (icp->icmp_type == ICMP_ECHOREPLY) {
if (icp->icmp_id != ident)
return; /* 'Twas not our ECHO */
++nreceived;
if (timing) {
#ifndef icmp_data
tp = (struct timeval *)(icp + 1);
#else
tp = (struct timeval *)icp->icmp_data;
#endif
tvsub(&tv, tp);
triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
tsum += triptime;
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
tmax = triptime;
}
if (TST(icp->icmp_seq % mx_dup_ck)) {
++nrepeats;
--nreceived;
dupflag = 1;
} else {
SET(icp->icmp_seq % mx_dup_ck);
dupflag = 0;
}
if (options & F_QUIET)
return;
if (options & F_FLOOD)
(void)write(STDOUT_FILENO, &BSPACE, 1);
else {
(void)printf("%d bytes from %s: icmp_seq=%u", cc,
inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
icp->icmp_seq);
(void)printf(" ttl=%d", ip->ip_ttl);
if (timing)
(void)printf(" time=%ld.%ld ms", triptime/10,
triptime%10);
if (dupflag)
(void)printf(" (DUP!)");
/* check the data */
#ifndef icmp_data
cp = ((u_char*)(icp + 1) + 8);
#else
cp = (u_char*)icp->icmp_data + 8;
#endif
dp = &outpack[8 + sizeof(struct timeval)];
for (i = 8; i < datalen; ++i, ++cp, ++dp) {
if (*cp != *dp) {
(void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
i, *dp, *cp);
cp = (u_char*)(icp + 1);
for (i = 8; i < datalen; ++i, ++cp) {
if ((i % 32) == 8)
(void)printf("\n\t");
(void)printf("%x ", *cp);
}
break;
}
}
}
} else {
/* We've got something other than an ECHOREPLY */
if (!(options & F_VERBOSE))
return;
(void)printf("%d bytes from %s: ", cc,
pr_addr(from->sin_addr.s_addr));
pr_icmph(icp);
}
/*#if 0*/
/* Display any IP options */
cp = (u_char *)buf + sizeof(struct iphdr);
for (; hlen > (int)sizeof(struct iphdr); --hlen, ++cp)
switch (*cp) {
case IPOPT_EOL:
hlen = 0;
break;
case IPOPT_LSRR:
(void)printf("\nLSRR: ");
hlen -= 2;
j = *++cp;
++cp;
if (j > IPOPT_MINOFF)
for (;;) {
l = *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
if (l == 0)
(void)printf("\t0.0.0.0");
else
(void)printf("\t%s", pr_addr(ntohl(l)));
hlen -= 4;
j -= 4;
if (j <= IPOPT_MINOFF)
break;
(void)putchar('\n');
}
break;
case IPOPT_RR:
j = *++cp; /* get length */
i = *++cp; /* and pointer */
hlen -= 2;
if (i > j)
i = j;
i -= IPOPT_MINOFF;
if (i <= 0)
continue;
if (i == old_rrlen
&& cp == (u_char *)buf + sizeof(struct iphdr) + 2
&& !memcmp((char *)cp, old_rr, i)
&& !(options & F_FLOOD)) {
(void)printf("\t(same route)");
i = ((i + 3) / 4) * 4;
hlen -= i;
cp += i;
break;
}
old_rrlen = i;
memcpy(old_rr, cp, i);
(void)printf("\nRR: ");
for (;;) {
l = *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
if (l == 0)
(void)printf("\t0.0.0.0");
else
(void)printf("\t%s", pr_addr(ntohl(l)));
hlen -= 4;
i -= 4;
if (i <= 0)
break;
(void)putchar('\n');
}
break;
case IPOPT_NOP:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?