1.Linux上的traceroute原理
UDP模式:UDP探测数据包(目标端口大于30000) + 中间网关发回 ICMP TTL 超时(ICMP Time Exceeded Message)数据包 + 目标主机发回ICMP Destination Unreachable 数据包
python_3">2.用到的python模块、库介绍
PS:报文是网络中交换和传输的数据单元,即站点一次性要发送的数据块。
Scapy
Scapy是一个由Python编写的强大工具,目前很多优秀的网络扫描攻击工具都使用了这个模块。也可以在自己的程序中使用这个模块来实现对网络数据包的发送、监听和解析。这个模块相对于Nmap来说,更为底层。可以更直观的了解网络中的各类扫描攻击行为。
相对于Nmap来说,Scapy模块只会把收到的数据包展示给你,并不会告诉你这个包意味着什么。
例如,当你去医院检查身体时,医院会给你一份关于身体各项指标的检查结果,而医生也会告诉你得了什么病或者没有任何病。那么Nmap就像是一个医生,它会替你搞定-切,按照它的经验提供给你结果。而Scapy则像是一个体检的设备, 它只会告诉你各种检查的结果,如果你自己就是一个经验丰富的医生,显然检查的结果要比同行的建议更值得参考。
具体用法见这篇文章
这篇也很好
解析回包内容
关于ICMP
3.Scapy下载
请看这篇文章
和这篇文章
4.编程实现
代码链接
python">#coding=utf-8
from scapy.all import *
import struct,re,random
# 首先构造一个发送一个UDP报文-接收ICMP报文-返回路由/主机ip及时间的函数
#函数返回 1,源地址,数据包发-收时间
def send_udp(dest_ip,ttl,dport): #参数:目的地址 ttl值 目的端口
#发送udp包开始时间
time1 = time.time() #当前系统时钟的时间戳(1970纪元后经过的浮点秒数)
try:
# 发送一个upd数据包,接收一个包
reply_ICMP = sr1(IP(dst=dest_ip, ttl=ttl) / UDP(dport=dport) / b'hello!', timeout=1,
verbose=False) #发送一个UPD数据包 dst目的地址 ttl值 dport目的端口 timeout=1超时1s丢弃 verbose=0不显示详细信息
# ICMP超时消息-数据包到达中间路由器
if reply_ICMP.getlayer(ICMP).type == 11 and reply_ICMP.getlayer(ICMP).code == 0:#ICMP差错报文-超时
# 提取ICMP包的源地址-即路由器ip
src_ip = reply_ICMP.getlayer(IP).src
#接收解析完icmp超时报文的时间
time2 = time.time() #当前系统时间戳
# 计算时间ms数
times = (time2-time1) * 1000 #从发送udp数据包,到接收ICMP超时报文所用时间
return 1,src_ip,times #返回一个元组
# ICMP端口不可达-数据包到达目的主机
elif reply_ICMP.getlayer(ICMP).type == 3 and reply_ICMP.getlayer(ICMP).code == 3:#ICMP差错报文-端口不可达
src_ip = reply_ICMP.getlayer(IP).src #获取ICMP包的源地址-即目的主机ip
time2 = time.time()
times= (time2-time1) * 1000
return 2, src_ip, times
except Exception as e:#捕获异常
return None
def traceroute(dest_ip,max_hop):#参数 目的地址 跳数限制
dest_port = 33434#目标端口号默认为33434 每次探测目标端口号+1
now_hop = 0 #记录当前跳数
ttl=0
# 进行循环发包-每次发三个探测包
while now_hop < max_hop: #循环hops次
now_hop += 1
ttl += 1
dest_port += 1
# 发送三个包,获取返回值
result1 = send_udp(dest_ip,ttl,dest_port) #目标地址 ttl值 目标端口
#result1
# 如果出现了错误,打印*号。
if result1 == None: #出现错误
print('*')
# 中间路由器的情况
elif result1[0] == 1:
print("%d %s %6.4fms" % (now_hop,result1[1],result1[2])) #跳数 路由器ip 数据包发-收时间(宽度为4,精确到小数点后2位)
# 到达目的端口的情况
elif result1[0] == 2:
print("%d %s %6.4fms" % (now_hop,result1[1],result1[2])) #跳数 目的地址 数据包发-收时间
break #退出程序
time.sleep(1) # 暂停1s
result2 = send_udp(dest_ip, ttl, dest_port) # 目标地址 ttl值 目标端口
# result2
# 如果出现了错误,打印*号。
if result2 == None: # 出现错误
print('*')
# 中间路由器的情况
elif result2[0] == 1:
print("%d %s %6.4fms" % (now_hop, result2[1], result2[2])) # 跳数 路由器ip 数据包发-收时间(宽度为4,精确到小数点后2位)
# 到达目的端口的情况
elif result2[0] == 2:
print("%d %s %6.4fms" % (now_hop, result2[1], result2[2])) # 跳数 目的地址 数据包发-收时间
break # 退出程序
time.sleep(1)#暂停1s
result3 = send_udp(dest_ip, ttl, dest_port) # 目标地址 ttl值 目标端口
# result3
# 如果出现了错误,打印*号。
if result3 == None: # 出现错误
print('*')
# 中间路由器的情况
elif result3[0] == 1:
print("%d %s %6.4fms" % (now_hop, result3[1], result3[2])) # 跳数 路由器ip 数据包发-收时间(宽度为8,精确到小数点后4位)
# 到达目的端口的情况
elif result3[0] == 2:
print("%d %s %6.4fms" % (now_hop, result3[1], result3[2])) # 跳数 目的地址 数据包发-收时间
break # 退出程序
time.sleep(1)#暂停1s
if __name__ == "__main__":
destination=input("请输入目的主机ip:")
max_hops=int(input("请输入跳数限制:"))
traceroute(destination,max_hops)
另一种方法