ping源码分析完整.doc

上传人:暗伤 文档编号:96356329 上传时间:2023-11-11 格式:DOC 页数:17 大小:88KB
返回 下载 相关 举报
ping源码分析完整.doc_第1页
第1页 / 共17页
ping源码分析完整.doc_第2页
第2页 / 共17页
点击查看更多>>
资源描述

《ping源码分析完整.doc》由会员分享,可在线阅读,更多相关《ping源码分析完整.doc(17页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、ping 源码分析10.4.1 ping简介Ping是网络中应用非常广泛的一个软件,它是基于ICMP协议的。下面首先对ICMP协议做一简单介绍。ICMP是IP层的一个协议,它是用来探测主机、路由维护、路由选择和流量控制的。ICMP报文的最终报宿不是报宿计算机上的一个用户进程,而是那个计算机上的IP层软件。也就是说,当一个带有错误信息的ICMP报文到达时,IP软件模块就处理本身问题,而不把这个ICMP报文传送给应用程序。ICMP报文类型有:回送(ECHO)回答(0);报宿不可到达(3);报源断开(4);重定向(改变路由)(5);回送(ECHO)请求(8);数据报超时(11);数据报参数问题(12

2、);时间印迹请求(13);时间印迹回答(14);信息请求(15);信息回答(16);地址掩码请求(17);地址掩码回答(18)。虽然每种报文都有不同的格式,但它们开始都有下面三段: 一个8位整数报文TYPE(类型)段; 一个8位CODE(代码码)段,提供更多的报文类型信息; 一个16 位CHECKSUM(校验和)段;此外,报告差错的ICMP 报文还包含产生问题数据报的网际报头及前64 位数据。一个ICMP回送请求与回送回答报文的格式如表10.17 所示。表10.17 ICMP回送请求与回送回答报文格式类型CODE 校验和CHECKSUM标识符序列号嵌入式Linux应用程序开发详解第10章、嵌入

3、式Linux网络编程数据10.4.2 ping源码分析下面的ping.c 源码是在busybox 里实现的源码。在这个完整的ping.c 代码中有较多选项的部分代码,因此,这里先分析除去选项部分代码的函数实现部分流程,接下来再给出完整的ping代码分析。这样,读者就可以看到一个完整协议实现应该考虑到的各个部分。1Ping 代码主体流程Ping.c主体流程图如下图10.8 所示。另外,由于ping是IP层的协议,因此在建立socket时需要使用SOCK_RAW 选项。在循环等待回应信息处,用户可以指定“-f”洪泛选项,这时就会使用select函数来指定在一定的时间内进行回应。2主要选项说明Pin

4、g函数主要有以下几个选项: d:调试选项(F_SO_DEBUG) f:洪泛选项(F_FLOOD) i:等待选项(F_INTERVAL) r:路由选项(F_RROUTE) l:广播选项(MULTICAST_NOLOOP)对于这些选项,尤其是路由选项、广播选项和洪泛选项都会有不同的实现代码。另外,ping 函数可以接受用户使用的SIGINT 和SIGALARM 信号来结束程序,它们分别指向了不同的结束代码,请读者阅读下面相关代码。图10.8 ping主体流程图3源代码及注释(1)主体代码ping代码的主体部分可以四部分,首先是一些头函数及宏定义:#include #include #include

5、 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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#de

6、fine F_SO_DONTROUTE 0x080#define F_VERBOSE 0x100/* 多播选项*/int moptions;#define MULTICAST_NOLOOP 0x001#define MULTICAST_TTL 0x002#define MULTICAST_IF 0x004嵌入式Linux应用程序开发详解第10章、嵌入式Linux网络编程接下来的第2 部分是建立socket并处理选项:Int main(int argc, char *argv)struct timeval timeout;struct hostent *hp;struct sockaddr_in

7、 *to;struct protoent *proto;struct in_addr ifaddr;int i;int ch, fdmask, hold, packlen, preload;u_char *datap, *packet;char *target, hnamebufMAXHOSTNAMELEN;u_char ttl, loop;int am_i_root;static char *null = NULL;/*_environ = &null;*/am_i_root = (getuid()=0);/*建立socket连接,并且测试是否是root用户*/if (s = socket(

8、AF_INET, SOCK_RAW, IPPROTO_ICMP) 0) if (errno=EPERM) fprintf(stderr, ping: ping must run as rootn);else perror(ping: socket);exit(2);preload = 0;datap = &outpack8 + 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 (np

9、ackets = 0) (void)fprintf(stderr,ping: bad number of packets to transmit.n);exit(2);break;/*调用选项*/case d:options |= F_SO_DEBUG;break;/*flood选项*/case f:if (!am_i_root) (void)fprintf(stderr,ping: %sn, strerror(EPERM);exit(2);options |= F_FLOOD;setbuf(stdout, NULL);break;/*等待选项*/case i: /* wait between

10、 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: %sn, strerror(EPERM);exit(2);preload = atoi(optarg);if (preload sin_family = AF_INET;/*地址转换函数*/if (inet

11、_aton(target, &to-sin_addr) hostname = target;else #if 0char * addr = resolve_name(target, 0);if (!addr) (void)fprintf(stderr,ping: unknown host %sn, target);exit(2);to-sin_addr.s_addr = inet_addr(addr);hostname = target;#else/*调用gethostbyname识别主机名*/hp = gethostbyname(target);if (!hp) (void)fprintf(

12、stderr,ping: unknown host %sn, 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;#endif接下来的一部分主要是对各个选项(如路由、

13、多播)的处理,这里就不做介绍了。再接下来是ping函数的最主要部分,就是接收无限循环回应信息,这里主要用到了函数recvfrom。另外,对用户中断信息也有相应的处理,如下所示:if (to-sin_family = AF_INET)(void)printf(PING %s (%s): %d data bytesn, hostname,inet_ntoa(*(struct in_addr *)&to-sin_addr.s_addr),datalen);else(void)printf(PING %s: %d data bytesn, hostname, datalen);/*若程序接收到SIGI

14、NT或SIGALRM信号,调用相关的函数*/(void)signal(SIGINT, finish);(void)signal(SIGALRM, catcher);/*循环等待客户端的回应信息*/for (;) struct sockaddr_in from;register int cc;int fromlen;if (options & F_FLOOD) /*形成ICMP回应数据包,在后面会有讲解*/pinger();/*设定等待实践*/timeout.tv_sec = 0;timeout.tv_usec = 10000;fdmask = 1 s;/*调用select函数*/嵌入式Linu

15、x应用程序开发详解第10章、嵌入式Linux网络编程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) = npackets)break;finish(0);/* NOTREACHED */return 0;(2)其他函数下面的函数也是p

16、ing 程序中用到的重要函数。首先catcher 函数是用户在发送SIGINT时调用的函数,在该函数中又调用了SIGALARM信号的处理来结束程序。static voidcatcher(int ignore)int waittime;(void)ignore;pinger();/*调用catcher函数*/(void)signal(SIGALRM, catcher);if (!npackets | ntransmitted MAXWAIT)waittime = MAXWAIT; elsewaittime = MAXWAIT;/*调用finish函数,并设定一定的等待实践*/(void)sign

17、al(SIGALRM, finish);(void)alarm(u_int)waittime);Pinger 函数也是一个非常重要的函数,用于形成ICMP回应数据包,其中ID 是该进程的ID,数据段中的前8 字节用于存放时间间隔,从而可以计算ping程序从对端返回的往返时延差,这里的数据校验用到了后面定义的in_cksum函数。其代码如下所示:static voidpinger(void)register struct icmphdr *icp;register int cc;int i;/*形成icmp信息包,填写icmphdr结构体中的各项数据*/icp = (struct icmphdr

18、 *)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 *)&outpack8,(struct timezone *)NULL);cc = datalen + 8; /* skips ICMP portion */嵌入式L

19、inux应用程序开发详解第10章、嵌入式Linux网络编程/* 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 ip_hl 2;if (cc sin_addr.s_addr);return;/* ICMP部分显示*/cc -= hlen;icp = (struct icmphdr *)(buf + hlen

20、);if (icp-icmp_type = ICMP_ECHOREPLY) if (icp-icmp_id != ident)return; /* Twas not our ECHO */+nreceived;if (timing) #ifndef icmp_datatp = (struct timeval *)(icp + 1);#elsetp = (struct timeval *)icp-icmp_data;#endiftvsub(&tv, tp);triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);tsum += triptime;if

21、(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;嵌入式Linux应用程序开发详解第10章、嵌入式Linux网络编程if (options & F_QUIET)return;if (options & F_FLOOD)(void)write(STDOUT_FILENO, &BSPACE, 1);else (void)printf(%d bytes from

22、 %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_datacp = (u_char*)(icp + 1) + 8);#elsecp = (u_c

23、har*)icp-icmp_data + 8;#endifdp = &outpack8 + 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 sin_addr.s_addr);pr_icmph(icp);/*#if 0*/*显示其他IP选项*/cp = (u_char *

24、)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 = (l8) + *+cp;l = (l8) + *+cp;l = (l8) + *+cp;if (l = 0)(void)printf(t0.0.0.0);e

25、lse(void)printf(t%s, pr_addr(ntohl(l);hlen -= 4;j -= 4;if (j 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_

26、rrlen = i;memcpy(old_rr, cp, i);(void)printf(nRR: );for (;) l = *+cp;l = (l8) + *+cp;l = (l8) + *+cp;l = (l8) + *+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 1) sum += *w+;nleft -= 2;if (nleft = 1) *(u_char *)(&answer) = *(u_char *)w ;sum += answ

27、er;/*把高16bit加到低16bit上去*/sum = (sum 16) + (sum & 0xffff);sum += (sum 16);answer = sum;return(answer);嵌入式Linux应用程序开发详解第10章、嵌入式Linux网络编程Finish程序是ping程序的结束程序,主要是打印出来一些统计信息,如下所示:static voidfinish(int ignore)(void)ignore;(void)signal(SIGINT, SIG_IGN);(void)putchar(n);(void)fflush(stdout);(void)printf(- %s

28、 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(- somebodys printing up packets!);else(void)printf(%d%

29、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.%ldmsn,tmin/10, tmin%10,(tsum / (nreceived + nrepeats)/10,(tsum / (nreceived + nrepeats)%10,tmax/10, tmax%10);if (nreceived=0) exit(1);

30、exit(0);#ifdef notdefstatic 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

31、 */Timestamp Reply, /* */Info Request, /* id + sq */Info Reply /* */;#endifpr_icmph函数是用于打印ICMP的回应信息,如下所示:static voidpr_icmph(struct icmphdr *icp)switch(icp-icmp_type) /*ICMP回应*/case ICMP_ECHOREPLY:(void)printf(Echo Replyn);/* XXX ID + Seq + Data */break;/*ICMP终点不可达*/case ICMP_DEST_UNREACH:switch(icp

32、-icmp_code) case ICMP_NET_UNREACH:(void)printf(Destination Net Unreachablen);break;case ICMP_HOST_UNREACH:(void)printf(Destination Host Unreachablen);break;case ICMP_PROT_UNREACH:(void)printf(Destination Protocol Unreachablen);break;default:(void)printf(Dest Unreachable, Unknown Code: %dn,icp-icmp_c

33、ode);break;/* Print returned IP header information */#ifndef icmp_datapr_retip(struct iphdr *)(icp + 1);#elsepr_retip(struct iphdr *)icp-icmp_data);#endifbreak;default:(void)printf(Redirect, Bad Code: %d, icp-icmp_code);break;(void)printf(New addr: %s)n,inet_ntoa(icp-icmp_gwaddr);#ifndef icmp_datapr

34、_retip(struct iphdr *)(icp + 1);#elsepr_retip(struct iphdr *)icp-icmp_data);#endifbreak;case ICMP_ECHO:(void)printf(Echo Requestn);/* XXX ID + Seq + Data */break;case ICMP_TIME_EXCEEDED:switch(icp-icmp_code) case ICMP_EXC_TTL:(void)printf(Time to live exceededn);break;case ICMP_EXC_FRAGTIME:(void)pr

35、intf(Frag reassembly time exceededn);break;default:(void)printf(Time exceeded, Bad Code: %dn,icp-icmp_code);break;default:(void)printf(Bad ICMP type: %dn, icp-icmp_type);pr_iph函数是用于打印IP数据包头选项,如下所示:static voidpr_iph(struct iphdr *ip)int hlen;u_char *cp;hlen = ip-ip_hl 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) & 0x1

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 技术方案

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com