最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何使用golang實現(xiàn)traceroute

 更新時間:2023年04月21日 11:39:32   作者:水番丘山  
這篇文章主要介紹了如何使用golang實現(xiàn)traceroute,該工具在linux環(huán)境下的命令是traceroute或者tracepath,在windows下命令是tracert,本文給大家詳細(xì)講解需要的朋友可以參考下

Traceroute 概念

traceroute是一種網(wǎng)絡(luò)診斷工具,通過traceroute可以診斷出本機(jī)到目的地IP之間的路由情況,例如路由跳數(shù)、延遲、是否可達(dá)等信息。該工具在linux環(huán)境下的命令是traceroute或者tracepath,在windows下命令是tracert

工作原理

traceroute在linux系列的操作系統(tǒng),默認(rèn)通過發(fā)送UDP請求到目的地IP,UDP的端口使用的是33434到33545之間。除了UDP的協(xié)議,可選用ICMP或者TCP(TCP SYN包)。使用33434到33534之間到端口是因為大部分linux系統(tǒng)的該范圍內(nèi)的端口是不可用的。正常情況下如果我們對一個目的地主機(jī)發(fā)起UDP請求,并且該端口不存在就會直接返回端口或者主機(jī)不可大的信息,這樣是無法獲取到中途的路由節(jié)點。此時需要引入一個TTL的概念。

TTL即Time-To-Live,更多的被理解為路由跳數(shù),該值存于IP頭,經(jīng)過路由轉(zhuǎn)發(fā)時會將該值減1,當(dāng)ttl值為0時,路由就會回復(fù)一個ICMP消息"Time Exceeded",表示跳數(shù)已經(jīng)達(dá)到最大值,無法進(jìn)行轉(zhuǎn)發(fā)。

IPV4報文

IPV4報文對TTL解釋

TTL在ipv4和ipv6頭有不同的定義,在ipv4頭用8位來存該數(shù)值,且命名為“Time to Live”,而在ipv6的頭則叫做“Hop Limit”。

IPV6報文

IPV6對于HopLimit的解釋

不管是Time to Live還是Hop Limit,其實都是相同的邏輯,路由轉(zhuǎn)發(fā)一次就減1,并且該值為0時則無法轉(zhuǎn)發(fā)。

我們來看一下traceroute的發(fā)包過程:

traceroute發(fā)包過程

第一步:主機(jī)A往目的主機(jī)B發(fā)送UDP包,包頭需要設(shè)置TTL=1,并且設(shè)置目的端口為33434。
第二步:主機(jī)A的最近的路由A收到UDP包以后,將TTL減1,此時TTL=0,路由A就將該包丟棄,并且回復(fù)主機(jī)A一條ICMP信息:“Time Exceeded”。
第三步:主機(jī)A收到ICMP的消息以后即可記錄ICMP發(fā)送主機(jī)的地址,該地址就是路由IP,并且主機(jī)A設(shè)置TTL=2,再次發(fā)送UDP包到目的主機(jī)B的33434端口。
第四步:以此類推,直到TTL超過設(shè)置的最大值或者收到目的主機(jī)返回的消息時停止發(fā)包,這樣就得到了一個路由地址列表,同時也能拿到發(fā)送到路由之間的消息延遲,如果路由超過設(shè)定的時間內(nèi)沒有相應(yīng),則置該跳數(shù)的路由地址為“*”。

traceroute-go代碼實現(xiàn)

由于go語言是高級語言,將udp以及tcp的包頭都封裝完整,無法定制設(shè)置ttl。好在golang提供了syscall庫,該庫提供依稀了linux下的函數(shù)調(diào)用,因此可以利用該包的方法達(dá)到設(shè)置ttl的目的。在1.4之前可以使用標(biāo)準(zhǔn)庫syscall,但因為該庫已經(jīng)被棄用,可以使用golang.org/x/sys庫,該庫是syscall的擴(kuò)展,提供更加豐富的系統(tǒng)調(diào)用方法。
有庫的支持,我們則需要了解一下C語言的知識,即用C語言發(fā)送udp包和接受icmp的信息,因此這里需要涉及到幾個函數(shù):

socket函數(shù),創(chuàng)建一個socke的文件描述,用于發(fā)送udp以及接收icmp的消息,golang對應(yīng)的函數(shù)為func Socket(domain, typ, proto int) (fd int, err error)setsockopt函數(shù),該函數(shù)可以用于設(shè)定IP的頭信息,我們要設(shè)定TTL就是利用該函數(shù),同時該函數(shù)可以設(shè)定socket的請求或者接收消息的超時時間,golang對應(yīng)的函數(shù)為func SetsockoptInt(fd, level, opt int, value int) (err error)sendto函數(shù),用于發(fā)送udp消息,golang對應(yīng)的函數(shù)為func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error)recvfrom函數(shù),用于接收icmp消息,golang對應(yīng)的函數(shù)為func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error)

函數(shù)準(zhǔn)備好以后就可以開工編寫golang版本的traceroute庫了。

首先,創(chuàng)建sendSocket,用于發(fā)送UDP包,注意內(nèi)部的參數(shù) unix.IPPROTO_UDP表示使用ipv4的udp協(xié)議,這個與ipv6協(xié)議是有區(qū)別的,可以通過命令man socket查看函數(shù)說明,然后創(chuàng)建一個recvSocket的socket文件描述符,用于接收ICMP的消息,這里調(diào)用了函數(shù)SetsockoptTimeval,用于設(shè)定接收消息的超時時間。

然后在for循環(huán)內(nèi)循環(huán)發(fā)送udp消息并且接收icmp消息:

代碼中SetsockoptInt函數(shù)設(shè)定ipv4的頭TTL,初始化ttl=1,通過Sendto函數(shù)將消息發(fā)送到目的地址和目的端口,這里目的端口從33434開始,會在33434到33534區(qū)間內(nèi)循環(huán)。

發(fā)送消息以后,通過Recvfrom接收消息,此時會判斷接收消息是否報錯,如果報錯則直接退出循環(huán)并結(jié)束traceroute操作;如果沒有報錯,則需要解析返回的ICMP消息,由于ipv4的Header包頭長度最小是20字節(jié),最大是60字節(jié),會出現(xiàn)浮動,因此需要拿到實際的ipv4頭長度,這里使用ipv4庫的ParseHeader函數(shù)解析拿到ipv4的包頭結(jié)構(gòu),然后將收到的消息截取ipHeader.Len長度就得到我們的ICMP消息結(jié)構(gòu)體,拿到ICMP消息結(jié)構(gòu)以后既可以根據(jù)Type判定消息類型,由于我們只關(guān)注ICMPTypeTimeExceededICMPTypeDestinationUnreachable類型的消息,因此其他消息我們都會丟棄,并且如果收到的是ICMPTypeTimeExceeded,則需要將發(fā)送方的地址(路由地址)存下來,并且將ttl+1,然后再次循環(huán)發(fā)送udp消息到目的地。
如果收到的ICMP消息類型是ICMPTypeDestinationUnreachable或者ttl超過了最大的ttl設(shè)定或者接受的的ICMP消息來自于目的地址,則結(jié)束發(fā)包,并輸出結(jié)果。

當(dāng)然,如果接收到報錯的消息,該消息可能是路由不通或者發(fā)包超時,因此我們需要將該跳的路由地址設(shè)置為“*”,同時判定重試次數(shù),以及是否超過了最大TTL。
最后每次循環(huán)都將目的端口值+1,并且超過了最大的端口33534是又從最小端口開始,保障端口范圍一直在33434到33534之間。

結(jié)果輸出:
以下是我們自己的程序結(jié)果輸出:

以下是系統(tǒng)自帶的traceroute輸出:

總結(jié)

traceroute工具原理不難,但要實現(xiàn)這個過程需要涉及到一些基本知識,如ip的報文組成、udp、icmp協(xié)議的一些基本知識,另外就是需要知道路由跳數(shù)的基本原理,通過實現(xiàn)這個過程也可以加深這些基礎(chǔ)知識,同時是對這些知識的運用。
完整代碼已經(jīng)上傳到github,地址為:https://github.com/Kseleven/traceroute-go,歡迎大家star,當(dāng)然如有紕漏或者講解不正確的地方,歡迎指正。

參考文獻(xiàn)

  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庫

到此這篇關(guān)于如何使用golang實現(xiàn)traceroute的文章就介紹到這了,更多相關(guān)golang實現(xiàn)traceroute內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang通脈之方法詳情

    Golang通脈之方法詳情

    這篇文章主要介紹了Golang通脈方法,Go語言中的方法(Method)是一種作用于特定類型變量的函數(shù)。這種特定類型變量叫做接收者(Receiver)。接收者的概念就類似于,其他語言中的this或者 self,具體內(nèi)容請和小編一起來學(xué)習(xí)下面文章內(nèi)容吧
    2021-10-10
  • Go項目實現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能

    Go項目實現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能

    無論是優(yōu)雅關(guān)機(jī)還是優(yōu)雅重啟歸根結(jié)底都是通過監(jiān)聽特定系統(tǒng)信號,然后執(zhí)行一定的邏輯處理保障當(dāng)前系統(tǒng)正在處理的請求被正常處理后再關(guān)閉當(dāng)前進(jìn)程,這篇文章主要介紹了Go實現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟 ,需要的朋友可以參考下
    2022-10-10
  • Go語言實現(xiàn)一個Http Server框架(二) Server的抽象

    Go語言實現(xiàn)一個Http Server框架(二) Server的抽象

    上一篇文章對http庫的基本使用做了說明,這篇文章主要介紹了如何實現(xiàn)一個簡單地httpServer,文中代碼示例非常詳細(xì),感興趣的朋友可以參考下
    2023-04-04
  • 使用Golang的channel交叉打印兩個數(shù)組的操作

    使用Golang的channel交叉打印兩個數(shù)組的操作

    這篇文章主要介紹了使用Golang的channel交叉打印兩個數(shù)組的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go如何實現(xiàn)Websocket服務(wù)以及代理

    Go如何實現(xiàn)Websocket服務(wù)以及代理

    這篇文章主要介紹了Go如何實現(xiàn)Websocket服務(wù)以及代理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • goLang引入自定義包的方法

    goLang引入自定義包的方法

    今天小編就為大家分享一篇goLang引入自定義包的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • 最新評論

    南部县| 梁河县| 凤阳县| 邵阳市| 老河口市| 阿拉善左旗| 龙海市| 肥乡县| 盘锦市| 叶城县| 墨竹工卡县| 迁安市| 大荔县| 河源市| 含山县| 阿图什市| 翁牛特旗| 四平市| 湄潭县| 汽车| 汉寿县| 柏乡县| 南岸区| 吉安市| 泾源县| 淅川县| 子长县| 曲水县| 醴陵市| 乌苏市| 新龙县| 长海县| 醴陵市| 浏阳市| 育儿| 五大连池市| 林周县| 胶南市| 郎溪县| 曲靖市| 海淀区|