📄 ping.c
字号:
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*/
/*显示其他IP选项 */
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:
(void)printf("\nNOP");
break;
default:
(void)printf("\nunknown option %x", *cp);
break;
}
/*#endif*/
if (!(options & F_FLOOD)) {
(void)putchar('\n');
(void)fflush(stdout);
}
}
in_cksum是数据校验程序,如下所示:
static int
in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
/*这里的算法很简单,就采用32bit的加法*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/*把高16bit加到低16bit上去*/
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
Finish程序是ping程序的结束程序,主要是打印出来一些统计信息,如下所示:
static void
finish(int ignore)
{
(void)ignore;
(void)signal(SIGINT, SIG_IGN);
(void)putchar('\n');
(void)fflush(stdout);
(void)printf("--- %s ping statistics ---\n", hostname);
(void)printf("%ld packets transmitted, ", ntransmitted);
(void)printf("%ld packets received, ", nreceived);
if (nrepeats)
(void)printf("+%ld duplicates, ", nrepeats);
if (ntransmitted)
if (nreceived > ntransmitted)
(void)printf("-- somebody's printing up packets!");
else
(void)printf("%d%% packet loss",
(int) (((ntransmitted - nreceived) * 100) /
ntransmitted));
(void)putchar('\n');
if (nreceived && timing)
(void)printf("round-trip min/avg/max = %ld.%ld/%lu.%ld/%ld.%ld ms\n",
tmin/10, tmin%10,
(tsum / (nreceived + nrepeats))/10,
(tsum / (nreceived + nrepeats))%10,
tmax/10, tmax%10);
if (nreceived==0) exit(1);
exit(0);
}
#ifdef notdef
static char *ttab[] = {
"Echo Reply", /* ip + seq + udata */
"Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
"Source Quench", /* IP */
"Redirect", /* redirect 类型, gateway, + IP */
"Echo",
"Time Exceeded", /*传输超时*/
"Parameter Problem", /* IP参数问题 */
"Timestamp", /* id + seq + three timestamps */
"Timestamp Reply", /* " */
"Info Request", /* id + sq */
"Info Reply" /* " */
};
#endif
pr_icmph函数是用于打印出ICMP回应信息,如下所示:
static void
pr_icmph(struct icmphdr *icp)
{
switch(icp->icmp_type) {
/*ICMP回应*/
case ICMP_ECHOREPLY:
(void)printf("Echo Reply\n");
/* XXX ID + Seq + Data */
break;
/*ICMP终点不可达*/
case ICMP_DEST_UNREACH:
switch(icp->icmp_code) {
case ICMP_NET_UNREACH:
(void)printf("Destination Net Unreachable\n");
break;
case ICMP_HOST_UNREACH:
(void)printf("Destination Host Unreachable\n");
break;
case ICMP_PROT_UNREACH:
(void)printf("Destination Protocol Unreachable\n");
break;
…
default:
(void)printf("Dest Unreachable, Unknown Code: %d\n",
icp->icmp_code);
break;
}
/* Print returned IP header information */
#ifndef icmp_data
pr_retip((struct iphdr *)(icp + 1));
#else
pr_retip((struct iphdr *)icp->icmp_data);
#endif
break;
…
default:
(void)printf("Redirect, Bad Code: %d", icp->icmp_code);
break;
}
(void)printf("(New addr: %s)\n",
inet_ntoa(icp->icmp_gwaddr));
#ifndef icmp_data
pr_retip((struct iphdr *)(icp + 1));
#else
pr_retip((struct iphdr *)icp->icmp_data);
#endif
break;
case ICMP_ECHO:
(void)printf("Echo Request\n");
/* XXX ID + Seq + Data */
break;
case ICMP_TIME_EXCEEDED:
switch(icp->icmp_code) {
case ICMP_EXC_TTL:
(void)printf("Time to live exceeded\n");
break;
case ICMP_EXC_FRAGTIME:
(void)printf("Frag reassembly time exceeded\n");
break;
default:
(void)printf("Time exceeded, Bad Code: %d\n",
icp->icmp_code);
break;
}
…
default:
(void)printf("Bad ICMP type: %d\n", icp->icmp_type);
}
}
pr_iph函数是用于打印IP数据包头选项,如下所示:
static void
pr_iph(struct iphdr *ip)
{
int hlen;
u_char *cp;
hlen = ip->ip_hl << 2;
cp = (u_char *)ip + 20; /* point to options */
(void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
(void)printf(" %1x %1x %02x %04x %04x",
ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
(void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
(ip->ip_off) & 0x1fff);
(void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
(void)printf(" %s ", inet_ntoa(*((struct in_addr *) &ip->ip_src)));
(void)printf(" %s ", inet_ntoa(*((struct in_addr *) &ip->ip_dst)));
/* dump and option bytes */
while (hlen-- > 20) {
(void)printf("%02x", *cp++);
}
(void)putchar('\n');
}
pr_addr是用于将ascii主机地址转换为十进制点分形式并打印出来,这里使用的函数是inet_ntoa,如下所示:
static char *
pr_addr(u_long l)
{
struct hostent *hp;
static char buf[256];
if ((options & F_NUMERIC) ||
!(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
(void)sprintf(buf, /*sizeof(buf),*/ "%s",inet_ntoa(*(struct in_addr *)&l));
else
(void)sprintf(buf, /*sizeof(buf),*/ "%s (%s)", hp->h_name,inet_ntoa(*(struct in_addr *)&l));
return(buf);
}
Usage函数是用于显示帮助信息,如下所示:
static void
usage(void)
{
(void)fprintf(stderr,
"usage: ping [-LRdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] [-t ttl] [-I interface address] host\n");
exit(2);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -