系列博客参考: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相关推荐

  1. 150集Linux网络编程培训视频吐血整理 | 网络基础

    学习视频来源:<黑马程序员 - Linux网络编程> 协议的概念 什么是协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则. 假设,A.B双方欲 ...

  2. 网络编程培训之六 使用原始套接字实现Ping

    系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400 代码以编号对应放在Github上:https://github.com ...

  3. 网络编程培训之三 实现TCP/UDP的简单Echo服务器

    系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400 代码以编号对应放在Github上:https://github.com ...

  4. 网络编程培训之一 编程实现IP/TCP/UDP报文

    系列博客参考:http://blog.csdn.net/zy416548283/article/category/1108400 代码以编号对应放在Github上:https://github.com ...

  5. python网络编程培训

    Python提供两个级别的网络访问. 底层网络服务支持基本套接字,它提供了所有标准BSDSocketsAPI访问底层操作系统的套接字接口的方式. SocketServer是一个高级网络服务模块,它提供 ...

  6. 【网络编程】之七、select聊天室

    好久没有用MFC 来写代码了,手都生疏了,悲剧啊,好多API 都去查的  哎~~~ 好了 下面把 我们聊天室的代码贴出: select函数封装: [cpp] view plaincopy BOOL C ...

  7. Muduo 网络编程示例之十:socks4a 代理服务器

    Muduo 网络编程示例之十:socks4a 代理服务器 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice  t.sina.com.cn/giantchen ...

  8. 编程培训正取代 CS 学位

    在过去几年中,移动互联网革命席卷全球,也拉动对移动软件(APP)开发的需求,从美国到中国,市面上也出现了编程培训机构.据美国媒体报道,美国大学计算机系的课程落后于市场需求,毕业生连续多年下降,而编程培 ...

  9. linux网络编程 华清,网络编程(华清远见内部培训资料).ppt

    网络编程(华清远见内部培训资料) 地址结构的一般用法 定义一个struct sockaddr_in类型的变量并清空 struct sockaddr_in myaddr; memset(&mya ...

最新文章

  1. 计算机原理及应用第三版pdf,计算机原理及运用.pdf
  2. Final变量的含义
  3. [摘抄]一些软件设计的原则
  4. Chrome浏览器手动添加Cookie的方法
  5. echo,print()和print_r()有什么区别?
  6. delphi 获取打印机默认纸张_Delphi 动态调整打印机纸张大小
  7. phpcmsV9发布文章后无法删除?后台找不到了?从phpmyadmin数据库删除吧!
  8. 第四季-专题21-USB驱动程序设计
  9. 华为鸿蒙智慧屏_华为智慧屏X65将于4月8日发布搭载了鸿蒙OS操作系统
  10. 三、第四节 创建https服务
  11. <<飞 鸟 集>> 泰戈尔
  12. 智慧果园系统——以水肥一体化系统功能为基础实现智慧果园系统项目 需求文档
  13. 《CCNA学习指南:数据中心(640-911)》——1.3 物理网络拓扑
  14. 破解大学寝室智能限电
  15. 自学java成功率高吗,为什么自学Java编程成功率那么低?
  16. 疫情导致招聘平台Xing的母公司New Work SE裁员
  17. c语言程序个人实验报告,C语言程序设计实验报告(5)
  18. 防止糖尿病的天然胰岛素——普洱熟茶
  19. xshell xftp 5系列
  20. ha456.jar打开dump文件报Unsupported major.minor version 51.0异常

热门文章

  1. Ansible剧本示例
  2. 【高效获取jpeg图片的尺寸】
  3. 登链钱包(一款功能强大的以太坊钱包)完全开源
  4. CSS最详细的基础教程
  5. android友盟微信授权登录清除,Android 微信,友盟授权;
  6. 番红-固绿染色(植物)
  7. 在线笔试神器~福利哟
  8. 什么模式下不可使用曝光补偿_摄影从零到入门 曝光模式与测光方法详解
  9. 老板电器携手华为HarmonyOS创新升级中国厨房新理念
  10. Bootstrap布局自动拉伸改变大小