我一直试图为python编写一个简单的跟踪路由实现;请找到下面的代码。
import socket
def main (HostName):
dest_addr = socket.gethostbyname(HostName)
TTL = 1 #Define the time to live as 1. Will be incremented by one after each UDP message has been sent
Max = 30
while True:
ICMP_socket = socket.socket(socket.AF_INET,socket.SOCK_RAW, socket.IPPROTO_ICMP) #Create socket that can receive ICMP
UDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) #Create socket that will send UDP messages
UDP.setsockopt(0,4,TTL)
ICMP_socket.bind(("",33434)) #33434 is the default port used for traceroute
message = "Hi" #The message we send is an empty string
UDP.sendto(message.encode(),(dest_addr, 33434))
Receiver = (0,"")
Router_addr = None
try:
Receiver = ICMP_socket.recvfrom(1024)
Router_addr = Receiver[1]
if Router_addr == None:
print("*")
else:
print(Router_addr)
except:
pass
finally:
ICMP_socket.close()
UDP.close()
TTL = TTL + 1
if Router_addr == dest_addr or TTL == Max:
break
if __name__ =="__main__":
main('google.com')我使用sudo在我的macOS终端上运行它,因为它需要根权限。然而,我得到的输出似乎是错误的。第一个ip是我的本地IP,第二个是我不知道的IP,其余的都是google的IP。它没有输出中间It,只有在达到TTL限制为30时才会中断。
这是输出(我删除了第一个Ip地址,即本地IP地址):
('172.30.224.110', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)
('172.217.19.46', 0)有人能帮忙吗?我似乎找不到这个问题。
谢谢!
发布于 2020-11-23 11:20:34
为什么程序不停止
当程序“到达”目的地时,程序不会停止,因为您忽略了address (您称之为Router_addr ),因为AF_INET是一个tuple (参见文档中的“套接字家族”)。问题中包含的输出(这是print(Router_addr)的结果)也可以看出这一点。
如果您将if Router_addr == dest_addr or TTL == Max:更新为如下所示,您的程序将停止。
if Router_addr[0] == dest_addr or TTL == Max:输出显示了什么
我不知道你的网络拓扑结构,你是如何到达互联网的,特别是谷歌。从您在输出中所描述和看到的内容来看。
172.30.224.110是提供商的路由器的内部接口(很可能)的私有IP地址;请记住,响应是从与您“更近”的接口发送到您的计算机的,而不是“更接近”因特网的响应(正如您提到的,您不承认此IP地址属于您的主机、大学路由器/网络)。为什么输出中的回送地址
如果您在路径中看到的某些网络主机(可能包括您的第一跳)是回送IP地址,而不是您发送数据包的地址,那么原因是下面的片段(以及后台发生了什么):
if Router_addr == None:
print("*")当网络节点没有响应时,socket.recvfrom()返回('127.0.0.1', 0),而不是None。这是因为对于UDP,ICMP Destination Unreachable (类型3) Port Unreachable (代码3)是由localhost生成的,而在目标端口没有监听的情况下。顺便说一句,这就是为什么ICMP_socket.recvfrom(1024)没有被阻塞的原因。
您修改过的程序,稍加修改,以打印TTL和ICMP类型和代码,给出(见, )。
$ sudo python3 trorig.py
('192.168.178.1', 0) TTL: [1] type: [11] code: [0]
('62.245.142.131', 0) TTL: [2] type: [11] code: [0]
('62.245.142.130', 0) TTL: [3] type: [11] code: [0]
('82.135.16.226', 0) TTL: [4] type: [11] code: [0]
('142.250.161.214', 0) TTL: [5] type: [11] code: [0]
('127.0.0.1', 0) TTL: [6] type: [3] code: [3]
('172.253.75.128', 0) TTL: [7] type: [11] code: [0]
('172.253.75.143', 0) TTL: [8] type: [11] code: [0]
('74.125.244.81', 0) TTL: [9] type: [11] code: [0]
('172.253.75.141', 0) TTL: [10] type: [11] code: [0]
('172.217.23.78', 0) TTL: [11] type: [3] code: [3]相应的tcpdump输出为(注意,无响应的网络主机没有行,142.250.161.214后面跟着172.253.75.128,):
$ sudo tcpdump -i en0 -nnn icmp
Password:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on en0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:30:45.720700 IP 192.168.178.1 > 192.168.178.20: ICMP time exceeded in-transit, length 38
14:30:45.740808 IP 62.245.142.131 > 192.168.178.20: ICMP time exceeded in-transit, length 38
14:30:45.761857 IP 62.245.142.130 > 192.168.178.20: ICMP time exceeded in-transit, length 36
14:30:45.782603 IP 82.135.16.226 > 192.168.178.20: ICMP time exceeded in-transit, length 36
14:30:45.803874 IP 142.250.161.214 > 192.168.178.20: ICMP time exceeded in-transit, length 38
14:30:53.454002 IP 172.253.75.128 > 192.168.178.20: ICMP time exceeded in-transit, length 76
14:30:53.476512 IP 172.253.75.143 > 192.168.178.20: ICMP time exceeded in-transit, length 38
14:30:53.496455 IP 74.125.244.81 > 192.168.178.20: ICMP time exceeded in-transit, length 38
14:30:53.519329 IP 172.253.75.141 > 192.168.178.20: ICMP time exceeded in-transit, length 38
14:30:53.541726 IP 172.217.23.78 > 192.168.178.20: ICMP 172.217.23.78 udp port 33434 unreachable, length 36相应的traceroute输出是(与上面的路径相比有一些不同,因为没有同时运行它,但问题仍然是,TTL: 6的网络主机是没有响应的):
$ traceroute -n google.com
traceroute to google.com (172.217.23.78), 64 hops max, 52 byte packets
1 192.168.178.1 8.694 ms 2.893 ms 3.095 ms
2 62.245.142.131 17.545 ms 17.361 ms 19.010 ms
3 62.245.142.130 25.948 ms 20.302 ms 26.077 ms
4 82.135.16.226 20.418 ms 19.967 ms 21.411 ms
5 142.250.161.214 29.145 ms 25.573 ms 19.979 ms
6 * * *
7 108.170.247.113 26.875 ms
172.253.75.146 21.736 ms
108.170.247.113 21.987 ms
8 172.253.75.143 22.435 ms
172.253.75.141 20.617 ms
108.170.247.120 21.670 ms
9 172.217.23.78 19.538 ms
74.125.244.97 18.503 ms
74.125.244.81 18.907 ms因此,您检查无响应网络主机的方式是不正确的。您可能希望将其更新为如下所示:
if Router_addr == ('127.0.0.1', 0) :
print("*")最后两点您可能需要考虑:
ICMP_socket.recvfrom(1024)中等待多长时间的超时时间。你可以看看socket.SO_RCVTIMEO。TTL上,可能有多个网络主机远离您的计算机到达目的地。您可能需要考虑发送多个数据包来发现它们(如果它们是可发现的)。编辑(回答下面的评论):原始代码需要一些小的修改才能没有问题地运行;下面是更新和增强的代码
import socket
import struct
def main (HostName):
dest_addr = socket.gethostbyname(HostName)
TTL = 1
Max = 30
while True:
ICMP_socket = socket.socket(socket.AF_INET,socket.SOCK_RAW, socket.IPPROTO_ICMP)
ICMP_socket.bind(("",33434))
UDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
UDP.setsockopt(0,4,TTL)
message = "Hi"
UDP.sendto(message.encode(),(dest_addr, 33434))
Router_addr = None
try:
Data, Router_addr = ICMP_socket.recvfrom(1024)
ICMP_header = Data[20:28]
type_, code, *_ = struct.unpack('bbHHh', ICMP_header)
if Router_addr == ('127.0.0.1', 0) :
print(f"* TTL: [{TTL}] type: [{type_}] code: [{code}]")
else:
print(f"{Router_addr} TTL: [{TTL}] type: [{type_}] code: [{code}]")
except Exception as e:
print(e)
finally:
ICMP_socket.close()
UDP.close()
TTL = TTL + 1
if Router_addr[0] == dest_addr or TTL == Max:
break
if __name__ =="__main__":
main('google.com')https://stackoverflow.com/questions/64959414
复制相似问题