<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
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",表示跳數已經達到最大值,無法進行轉發。
TTL在ipv4和ipv6頭有不同的定義,在ipv4頭用8位元來存該數值,且命名為“Time to Live”,而在ipv6的頭則叫做“Hop Limit”。
不管是Time to Live還是Hop Limit,其實都是相同的邏輯,路由轉發一次就減1,並且該值為0時則無法轉發。
我們來看一下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超過設定的最大值或者收到目的主機返回的訊息時停止發包,這樣就得到了一個路由地址列表,同時也能拿到傳送到路由之間的訊息延遲,如果路由超過設定的時間內沒有相應,則置該跳數的路由地址為“*”。
由於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判定訊息型別,由於我們只關注ICMPTypeTimeExceeded
和ICMPTypeDestinationUnreachable
型別的訊息,因此其他訊息我們都會丟棄,並且如果收到的是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,當然如有紕漏或者講解不正確的地方,歡迎指正。
到此這篇關於如何使用golang實現traceroute的文章就介紹到這了,更多相關golang實現traceroute內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45