# 這個腳本是實現Linux中traceroute程序的,是探測從咱們這個機器到咱們要探測的IP地址中間都須要通過那些路由。
# 原理:咱們的機器發送UDP高端口的數據包,發送給目的地址,首先設置ttl爲1,而後逐次增長,在沒有到達咱們的目的IP
# 地址的路由,會發送ICMP的超時報文,而後咱們從中提取IP地址,由於咱們發送的是高端口的報文,到達目的地址的時候,
# 目的地址會發送ICMP的端口不可達報文,這樣咱們就探測出從咱們源端口到目的端口的路由。
from scapy.all import *
import struct,re,random
# 跟咱們實現ping程序的想法是同樣的,首先構造一個發送一個UDP報文的函數,
# 入參爲目的地址,ttl數。
def traceroute_one(dst,ttl_no,dport):
# 定義發包時間。
send_time = time.time()
try:
# 發送一個包,接收一個包。
traceroute_one_reply = sr1(IP(dst=dst, ttl=ttl_no) / UDP(dport=dport) / b'hello world', timeout=1,
verbose=False)
# 判斷ICMP包是否是超時回答。
if traceroute_one_reply.getlayer(ICMP).type == 11 and traceroute_one_reply.getlayer(ICMP).code == 0:
# 提取源地址
src_ip = traceroute_one_reply.getlayer(IP).src
# 定義接收時間。
recv_time = time.time()
# 計算時間ms數
mid_time = (recv_time - send_time) * 1000
# 返回。
return 1,src_ip,mid_time
# 這裏接接收的是最後一跳。ICMP應該是端口不可達。
elif traceroute_one_reply.getlayer(ICMP).type == 3 and traceroute_one_reply.getlayer(ICMP).code == 3:
# 下邊處理是同樣的。
src_ip = traceroute_one_reply.getlayer(IP).src
recv_time = time.time()
mid_time = (recv_time - send_time) * 1000
return 2, src_ip, mid_time
except Exception as e:
return None
def traceroute(dst,hops):
# 目的端口從33434開始算起,入參爲目的地址,咱們想要查找的路由的條數。
dport = 33434
hop = 0
# 進行循環包。
while hop < hops:
hop += 1
# 這裏須要改變端口。
dport += hop
# 發送一個包,獲取返回值。
traceroute_result = traceroute_one(dst,hop,dport)
# 若是出現了錯誤,打印*號。
if traceroute_result == None:
print('*')
# 這裏表明中間路由,咱們進行打印信息。
elif traceroute_result[0] == 1:
print("%d %s %4.2fms" % (hop,traceroute_result[1],traceroute_result[2]))
# 最後一個包,爲端口不可達,打印信息後,須要退出循環,由於已經到達目的地址了,雖然可能沒有達到咱們定義的條數。
elif traceroute_result[0] == 2:
print("%d %s %4.2fms" % (hop, traceroute_result[1], traceroute_result[2]))
break
time.sleep(1)
if __name__ == "__main__":
traceroute('180.101.49.12',10)
# 接下來咱們就能夠使用wirshark進行抓包來看一下。
