网络编程培训之七 实现Traceroute
系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400
代码以编号对应放在Github上:https://github.com/zy416548283/networkProgramming
题目
编程实现Traceroute的基本功能
题目解读
- 首先了解traceroute的基本用法和功能,我们来man一下:
traceroute tracks the route packets taken from an IP network on their way to a given host.
It utilizes the IP protocol's time to live (TTL) field and attempts to elicit an ICMP TIME_EXCEEDED response from each gateway along the path to the host.
- 了解traceroute的实现原理,可以参考[TCP/IP详解 卷一]
- 根据原理,编程实现traceroute
实现
原理
traceroute一开始向目的地发送一个TTL为1的UDP数据报,这个数据报在第一跳路由器返回一个超时的ICMP报文,并丢弃该报文.发送方解析这个ICMP报文(每个进程都会从内核收到一个消息的副本),如果是超时ICMP消息,将递增TTL一次,直到到达目标主机,此时目标主机会回复一个端口不可达的ICMP报文(发送的UDP报文会选择端口比较大,并且变化的端口),发送方解析ICMP端口不可达报文,打印对应的数据.
主流程
- 处理命令行参数/处理主机名或者IP地址;
- 做一些初始化工作;
- 进入循环
循环
- 创建两个套接字:一个原始套接字用于读取返送的ICMP消息;另外一个套接字用于发送探测分组的UDP套接字;
- 对TTL进行循环递增直到TTL达到最大或者到达目的地, 并且对于每个TTL发送3个UDP数据报的探测分组. 发送一个探测分组之后等待3秒钟来接收ICMP消息,然后才发送下一个探测分组.
- 关于没有收到ICMP回应报文的情况,这样处理:
if ( (code = (*pr->recv)(seq, &tvrecv)) == -3)printf(" *"); /* timeout, no reply */
- 关于解析ICMP消息的函数如下:
int
recv_v4(int seq, struct timeval *tv)
{int hlen1, hlen2, icmplen, ret;socklen_t len;ssize_t n;struct ip *ip, *hip;struct icmp *icmp;struct udphdr *udp;gotalarm = 0;alarm(3);for ( ; ; ) {if (gotalarm)return(-3); /* alarm expired */len = pr->salen;n = recvfrom(recvfd, recvbuf, sizeof(recvbuf), 0, pr->sarecv, &len);if (n < 0) {if (errno == EINTR)continue;elseerr_sys("recvfrom error");}ip = (struct ip *) recvbuf; /* start of IP header */hlen1 = ip->ip_hl << 2; /* length of IP header */icmp = (struct icmp *) (recvbuf + hlen1); /* start of ICMP header */if ( (icmplen = n - hlen1) < 8)continue; /* not enough to look at ICMP header */if (icmp->icmp_type == ICMP_TIMXCEED &&icmp->icmp_code == ICMP_TIMXCEED_INTRANS) {if (icmplen < 8 + sizeof(struct ip))continue; /* not enough data to look at inner IP */hip = (struct ip *) (recvbuf + hlen1 + 8);hlen2 = hip->ip_hl << 2;if (icmplen < 8 + hlen2 + 4)continue; /* not enough data to look at UDP ports */udp = (struct udphdr *) (recvbuf + hlen1 + 8 + hlen2);if (hip->ip_p == IPPROTO_UDP &&udp->uh_sport == htons(sport) &&udp->uh_dport == htons(dport + seq)) {ret = -2; /* we hit an intermediate router */break;}} else if (icmp->icmp_type == ICMP_UNREACH) {if (icmplen < 8 + sizeof(struct ip))continue; /* not enough data to look at inner IP */hip = (struct ip *) (recvbuf + hlen1 + 8);hlen2 = hip->ip_hl << 2;if (icmplen < 8 + hlen2 + 4)continue; /* not enough data to look at UDP ports */udp = (struct udphdr *) (recvbuf + hlen1 + 8 + hlen2);if (hip->ip_p == IPPROTO_UDP &&udp->uh_sport == htons(sport) &&udp->uh_dport == htons(dport + seq)) {if (icmp->icmp_code == ICMP_UNREACH_PORT)ret = -1; /* have reached destination */elseret = icmp->icmp_code; /* 0, 1, 2, ... */break;}}if (verbose) {printf(" (from %s: type = %d, code = %d)\n",Sock_ntop_host(pr->sarecv, pr->salen),icmp->icmp_type, icmp->icmp_code);}/* Some other ICMP error, recvfrom() again */}alarm(0); /* don't leave alarm running */Gettimeofday(tv, NULL); /* get time of packet arrival */return(ret);
}
可以看到代码中会像Ping中一样去解析报文,处理ICMP的超时错误以及端口不可达错误.
编译运行
root@zy:/home/zy/code/unp/unpv13e/traceroute# gcc main.c traceloop.c tv_sub.c sig_alrm.c recv_v4.c recv_v6.c icmpcode_v4.c icmpcode_v6.c -o mytraceroute -lunp
root@zy:/home/zy/code/unp/unpv13e/traceroute# ./mytraceroute 121.49.97.129
traceroute to 121.49.97.129 (121.49.97.129): 30 hops max, 12 data bytes1 192.168.1.2 (192.168.1.2) 0.236 ms 0.206 ms 0.203 ms2 121.49.97.129 (121.49.97.129) 0.786 ms * 0.824 ms
root@zy:/home/zy/code/unp/unpv13e/traceroute#
如果觉得文章对你有帮助,可以通过支付宝打赏点:
网络编程培训之七 实现Traceroute相关推荐
- 150集Linux网络编程培训视频吐血整理 | 网络基础
学习视频来源:<黑马程序员 - Linux网络编程> 协议的概念 什么是协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则. 假设,A.B双方欲 ...
- 网络编程培训之六 使用原始套接字实现Ping
系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400 代码以编号对应放在Github上:https://github.com ...
- 网络编程培训之三 实现TCP/UDP的简单Echo服务器
系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400 代码以编号对应放在Github上:https://github.com ...
- 网络编程培训之一 编程实现IP/TCP/UDP报文
系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400 代码以编号对应放在Github上:https://github.com ...
- python网络编程培训
Python提供两个级别的网络访问. 底层网络服务支持基本套接字,它提供了所有标准BSDSocketsAPI访问底层操作系统的套接字接口的方式. SocketServer是一个高级网络服务模块,它提供 ...
- 【网络编程】之七、select聊天室
好久没有用MFC 来写代码了,手都生疏了,悲剧啊,好多API 都去查的 哎~~~ 好了 下面把 我们聊天室的代码贴出: select函数封装: [cpp] view plaincopy BOOL C ...
- Muduo 网络编程示例之十:socks4a 代理服务器
Muduo 网络编程示例之十:socks4a 代理服务器 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice t.sina.com.cn/giantchen ...
- 编程培训正取代 CS 学位
在过去几年中,移动互联网革命席卷全球,也拉动对移动软件(APP)开发的需求,从美国到中国,市面上也出现了编程培训机构.据美国媒体报道,美国大学计算机系的课程落后于市场需求,毕业生连续多年下降,而编程培 ...
- linux网络编程 华清,网络编程(华清远见内部培训资料).ppt
网络编程(华清远见内部培训资料) 地址结构的一般用法 定义一个struct sockaddr_in类型的变量并清空 struct sockaddr_in myaddr; memset(&mya ...
最新文章
- 计算机原理及应用第三版pdf,计算机原理及运用.pdf
- Final变量的含义
- [摘抄]一些软件设计的原则
- Chrome浏览器手动添加Cookie的方法
- echo,print()和print_r()有什么区别?
- delphi 获取打印机默认纸张_Delphi 动态调整打印机纸张大小
- phpcmsV9发布文章后无法删除?后台找不到了?从phpmyadmin数据库删除吧!
- 第四季-专题21-USB驱动程序设计
- 华为鸿蒙智慧屏_华为智慧屏X65将于4月8日发布搭载了鸿蒙OS操作系统
- 三、第四节 创建https服务
- <<飞 鸟 集>> 泰戈尔
- 智慧果园系统——以水肥一体化系统功能为基础实现智慧果园系统项目 需求文档
- 《CCNA学习指南:数据中心(640-911)》——1.3 物理网络拓扑
- 破解大学寝室智能限电
- 自学java成功率高吗,为什么自学Java编程成功率那么低?
- 疫情导致招聘平台Xing的母公司New Work SE裁员
- c语言程序个人实验报告,C语言程序设计实验报告(5)
- 防止糖尿病的天然胰岛素——普洱熟茶
- xshell xftp 5系列
- ha456.jar打开dump文件报Unsupported major.minor version 51.0异常