一跳一跳探
(这一节多了逐跳模拟:NODES 里每个节点有接口地址和一张小路由表;next_hop 在某节点上查表,owner 找哪个节点持有某个地址,trace 从起点一跳跳走到目标,交回 (路径, 结果)。)
贯穿拓扑:
主机 192.168.10.5/24
└─ R1 192.168.10.1 | 10.0.1.1
└─ R2 10.0.1.2 | 10.0.2.1
└─ R3 10.0.2.2 | 172.16.0.1
└─ 目标 172.16.0.9/24模拟 traceroute:TTL 从 1 起,每次看包停在了谁那里,直到到达:
def to_int(ip):
a, b, c, d = [int(x) for x in ip.split(".")]
return (a << 24) | (b << 16) | (c << 8) | d
def mask(prefix):
return (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF
def contains(cidr, ip):
net, p = cidr.split("/")
return to_int(net) & mask(int(p)) == to_int(ip) & mask(int(p))
NODES = {
"主机": (["192.168.10.5/24"], [("0.0.0.0/0", "192.168.10.1")]),
"R1": (["192.168.10.1/24", "10.0.1.1/24"], [("172.16.0.0/16", "10.0.1.2"), ("0.0.0.0/0", "10.0.1.2")]),
"R2": (["10.0.1.2/24", "10.0.2.1/24"], [("172.16.0.0/16", "10.0.2.2"), ("192.168.10.0/24", "10.0.1.1")]),
"R3": (["10.0.2.2/24", "172.16.0.1/24"], [("192.168.10.0/24", "10.0.2.1")]),
"目标": (["172.16.0.9/24"], [("0.0.0.0/0", "172.16.0.1")]),
}
def owner(nodes, ip):
for name, (addrs, _) in nodes.items():
if any(a.split("/")[0] == ip for a in addrs):
return name
return None
def next_hop(nodes, name, target):
addrs, table = nodes[name]
for a in addrs:
if contains(a, target):
return "直连"
best = None
for cidr, via in table:
if contains(cidr, target):
plen = int(cidr.split("/")[1])
if best is None or plen > best[0]:
best = (plen, via)
return best[1] if best else None
def trace(nodes, start, target, ttl=16):
path = [start]
cur = start
while ttl > 0:
hop = next_hop(nodes, cur, target)
if hop is None:
return path, "无路可走"
if hop == "直连":
dst = owner(nodes, target)
if dst is None:
return path, "同段但无人应答"
path.append(dst)
return path, "到达"
cur = owner(nodes, hop)
if cur is None:
return path, "下一跳不存在"
path.append(cur)
ttl -= 1
return path, "TTL耗尽"
def trace_ttl(nodes, start, target, ttl):
path = [start]
cur = start
while ttl > 0:
hop = next_hop(nodes, cur, target)
if hop is None:
return path, "无路可走"
if hop == "直连":
path.append(owner(nodes, target))
return path, "到达"
cur = owner(nodes, hop)
path.append(cur)
ttl -= 1
return path, "TTL耗尽"
seen = []
ttl = 1
while True:
path, result = trace_ttl(NODES, "主机", "172.16.0.9", ttl)
seen.append(path[-1])
if result == "到达":
break
ttl += 1
print(",".join(seen) + "/" + str(ttl))
全部评论