我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何使用golang实现traceroute

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何使用golang实现traceroute

Traceroute 概念

traceroute是一种网络诊断工具,通过traceroute可以诊断出本机到目的地IP之间的路由情况,例如路由跳数、延迟、是否可达等信息。该工具在linux环境下的命令是traceroute或者tracepath,在windows下命令是tracert

工作原理

traceroute在linux系列的操作系统,默认通过发送UDP请求到目的地IP,UDP的端口使用的是33434到33545之间。除了UDP的协议,可选用ICMP或者TCP(TCP SYN包)。使用33434到33534之间到端口是因为大部分linux系统的该范围内的端口是不可用的。正常情况下如果我们对一个目的地主机发起UDP请求,并且该端口不存在就会直接返回端口或者主机不可大的信息,这样是无法获取到中途的路由节点。此时需要引入一个TTL的概念。

TTL即Time-To-Live,更多的被理解为路由跳数,该值存于IP头,经过路由转发时会将该值减1,当ttl值为0时,路由就会回复一个ICMP消息"Time Exceeded",表示跳数已经达到最大值,无法进行转发。

IPV4报文

IPV4报文对TTL解释

TTL在ipv4和ipv6头有不同的定义,在ipv4头用8位来存该数值,且命名为“Time to Live”,而在ipv6的头则叫做“Hop Limit”。

IPV6报文

IPV6对于HopLimit的解释

不管是Time to Live还是Hop Limit,其实都是相同的逻辑,路由转发一次就减1,并且该值为0时则无法转发。

我们来看一下traceroute的发包过程:

traceroute发包过程

第一步:主机A往目的主机B发送UDP包,包头需要设置TTL=1,并且设置目的端口为33434。
第二步:主机A的最近的路由A收到UDP包以后,将TTL减1,此时TTL=0,路由A就将该包丢弃,并且回复主机A一条ICMP信息:“Time Exceeded”。
第三步:主机A收到ICMP的消息以后即可记录ICMP发送主机的地址,该地址就是路由IP,并且主机A设置TTL=2,再次发送UDP包到目的主机B的33434端口。
第四步:以此类推,直到TTL超过设置的最大值或者收到目的主机返回的消息时停止发包,这样就得到了一个路由地址列表,同时也能拿到发送到路由之间的消息延迟,如果路由超过设定的时间内没有相应,则置该跳数的路由地址为“*”。

traceroute-go代码实现

由于go语言是高级语言,将udp以及tcp的包头都封装完整,无法定制设置ttl。好在golang提供了syscall库,该库提供依稀了linux下的函数调用,因此可以利用该包的方法达到设置ttl的目的。在1.4之前可以使用标准库syscall,但因为该库已经被弃用,可以使用golang.org/x/sys库,该库是syscall的扩展,提供更加丰富的系统调用方法。
有库的支持,我们则需要了解一下C语言的知识,即用C语言发送udp包和接受icmp的信息,因此这里需要涉及到几个函数:

socket函数,创建一个socke的文件描述,用于发送udp以及接收icmp的消息,golang对应的函数为func Socket(domain, typ, proto int) (fd int, err error)setsockopt函数,该函数可以用于设定IP的头信息,我们要设定TTL就是利用该函数,同时该函数可以设定socket的请求或者接收消息的超时时间,golang对应的函数为func SetsockoptInt(fd, level, opt int, value int) (err error)sendto函数,用于发送udp消息,golang对应的函数为func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error)recvfrom函数,用于接收icmp消息,golang对应的函数为func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error)

函数准备好以后就可以开工编写golang版本的traceroute库了。

首先,创建sendSocket,用于发送UDP包,注意内部的参数 unix.IPPROTO_UDP表示使用ipv4的udp协议,这个与ipv6协议是有区别的,可以通过命令man socket查看函数说明,然后创建一个recvSocket的socket文件描述符,用于接收ICMP的消息,这里调用了函数SetsockoptTimeval,用于设定接收消息的超时时间。

然后在for循环内循环发送udp消息并且接收icmp消息:

代码中SetsockoptInt函数设定ipv4的头TTL,初始化ttl=1,通过Sendto函数将消息发送到目的地址和目的端口,这里目的端口从33434开始,会在33434到33534区间内循环。

发送消息以后,通过Recvfrom接收消息,此时会判断接收消息是否报错,如果报错则直接退出循环并结束traceroute操作;如果没有报错,则需要解析返回的ICMP消息,由于ipv4的Header包头长度最小是20字节,最大是60字节,会出现浮动,因此需要拿到实际的ipv4头长度,这里使用ipv4库的ParseHeader函数解析拿到ipv4的包头结构,然后将收到的消息截取ipHeader.Len长度就得到我们的ICMP消息结构体,拿到ICMP消息结构以后既可以根据Type判定消息类型,由于我们只关注ICMPTypeTimeExceededICMPTypeDestinationUnreachable类型的消息,因此其他消息我们都会丢弃,并且如果收到的是ICMPTypeTimeExceeded,则需要将发送方的地址(路由地址)存下来,并且将ttl+1,然后再次循环发送udp消息到目的地。
如果收到的ICMP消息类型是ICMPTypeDestinationUnreachable或者ttl超过了最大的ttl设定或者接受的的ICMP消息来自于目的地址,则结束发包,并输出结果。

当然,如果接收到报错的消息,该消息可能是路由不通或者发包超时,因此我们需要将该跳的路由地址设置为“*”,同时判定重试次数,以及是否超过了最大TTL。
最后每次循环都将目的端口值+1,并且超过了最大的端口33534是又从最小端口开始,保障端口范围一直在33434到33534之间。

结果输出:
以下是我们自己的程序结果输出:

以下是系统自带的traceroute输出:

总结

traceroute工具原理不难,但要实现这个过程需要涉及到一些基本知识,如ip的报文组成、udp、icmp协议的一些基本知识,另外就是需要知道路由跳数的基本原理,通过实现这个过程也可以加深这些基础知识,同时是对这些知识的运用。
完整代码已经上传到github,地址为:https://github.com/Kseleven/traceroute-go,欢迎大家star,当然如有纰漏或者讲解不正确的地方,欢迎指正。

参考文献

  1. ipv4 rfc 791
  2. ipv6 rfc 2460
  3. icmp rfc 792
  4. traceroute rfc 1393
  5. linux man page-traceroute
  6. traceroute wiki
  7. icmp wiki
  8. golang sys库

到此这篇关于如何使用golang实现traceroute的文章就介绍到这了,更多相关golang实现traceroute内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何使用golang实现traceroute

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何使用golang实现traceroute

这篇文章主要介绍了如何使用golang实现traceroute,该工具在linux环境下的命令是traceroute或者tracepath,在windows下命令是tracert,本文给大家详细讲解需要的朋友可以参考下
2023-05-17

如何使用Linux中traceroute命令

本篇内容主要讲解“如何使用Linux中traceroute命令”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何使用Linux中traceroute命令”吧!关于linux traceroute
2023-06-09

Linux中如何使用traceroute命令

小编给大家分享一下Linux中如何使用traceroute命令,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Linux常用命令traceroute命令用于显示数据包到主机间的路径,traceroute指令让你追踪网络数据包
2023-06-28

如何使用Golang实现NFT

今天小编给大家分享一下如何使用Golang实现NFT的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、什么是NFTNFT是一
2023-07-06

traceroute命令如何在Linux中使用

本篇文章为大家展示了traceroute命令如何在Linux中使用,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Linux traceroute命令使用方法实例详解一、默认使用的是UDP协议(300
2023-06-09

如何在Linux中使用traceroute命令

这篇文章给大家介绍如何在Linux中使用traceroute命令,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1.命令格式:traceroute[参数][主机]2.命令功能:traceroute指令让你追踪网络数据包的
2023-06-13

使用 Golang 实现文件上传进度条如何实现?

golang 中实现文件上传进度条需要以下步骤:下载 github.com/gin-gonic/gin 和 github.com/go-bindata/go-bindata 包;导入这些包并定义一个处理上传请求的函数;在 html 页面中创
使用 Golang 实现文件上传进度条如何实现?
2024-05-13

如何使用 Golang 函数类型实现回调?

是的,在 go 中可以使用函数类型实现回调功能,具体步骤如下:声明一个函数类型,指定回调函数的签名。定义一个接受函数类型作为参数的函数。将需要回调的函数传递给该函数。使用 Golang 函数类型实现回调在 Go 中,函数类型允许您将函数声
如何使用 Golang 函数类型实现回调?
2024-04-22

如何使用 Golang 构建 RESTful API 并实现 CORS?

创建 restful api 并实现 cors:创建项目并安装依赖项。设置 http 路由处理请求。使用 middlewarecors 中间件启用跨域资源共享 (cors)。将 cors 中间件应用于路由器,允许来自任何域的 get 和 o
如何使用 Golang 构建 RESTful API 并实现 CORS?
2024-05-15

如何使用 Golang 实现异步文件上传?

如何用 go 实现异步文件上传?使用 http.multipartfile 处理文件上传,它支持并发上传。创建一个 goroutine 来异步上传文件,不会阻塞主线程。使用 io.copy 将文件内容写入新文件。上传成功后打印日志消息。如何
如何使用 Golang 实现异步文件上传?
2024-05-13

Linux traceroute命令使用方法实例详解

Linux traceroute命令使用方法实例详解 一、默认使用的是UDP协议(30000以上端口)二、使用TCP协议-T -p三、使用ICMP协议-I四、实战[root@localhost hping-master]# whereis
2022-06-04

如何使用Golang Facade实现简洁的接口调用

使用Golang的Facade模式可以实现简洁的接口调用。Facade模式是一种结构设计模式,它提供了一种简化接口的方式,使得客户端可以更方便地使用系统的功能。下面是一个使用Golang Facade实现简洁的接口调用的示例代码:首先,我们
2023-10-10

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录