我正在玩一款名为“Planetside 2”的游戏,几天以来,包括我在内的许多用户在特定服务器上都遇到了高 ping 问题,而其他用户则没有。
因此我想尝试跟踪路由/ping 服务器 IP,以找出哪个服务器节点导致了高 ping 问题。
但是,服务器似乎有某种防火墙,可以保护自己免受 ICMP 的 ping 攻击。每当我使用“ping 69.174.216.23”(该 IP 在 Google 上是公开的,因此我可以在此处分享)时,我都会收到超时响应。
因此我使用 Wireshark 来找出游戏客户端如何与服务器通信,我发现它正在使用 UDP 来 ping 服务器 IP:端口。
但是,服务器仅开放了几个端口,例如服务器 IP:69.174.216.23,它仅与以下端口进行通信:{20112、20113、20143、20156、20157、20164、20168、20175}
如果我模拟这一点,向服务器发送一个 1 字节的 UDP 数据包,它不起作用,但如果我在其后面添加一个端口 69.174.216.23:20112 并发送一个 1 字节的 UDP 数据包,我就会收到响应。
我编写了一个简单的 Python 脚本,它可以很好地完成这个目的:
import socket
import time
def udp_ping(destination_ip, destination_port):
try:
# Create a UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Set a timeout for receiving responses (in seconds)
udp_socket.settimeout(5)
# Record the time just before sending the message
start_time = time.time()
# Send a message to the destination
udp_socket.sendto(b'PONG', (destination_ip, destination_port))
# Receive a response
response, address = udp_socket.recvfrom(1024)
# Record the time when the response is received
end_time = time.time()
# Calculate round-trip time (RTT) in milliseconds
rtt_ms = (end_time - start_time) * 1000
print("Received response from {}: {} (RTT: {:.2f} ms)".format(address, response.decode(), rtt_ms))
except socket.timeout:
print("No response received.")
finally:
udp_socket.close()
destination_ip = '69.174.216.23'
destination_port = 20112
udp_ping(destination_ip, destination_port)
因此,由于我无法使用 ICMP 跟踪路由或 ping 服务器 IP,我想知道是否还有其他可能的方法,比如使用像我对 udp ip:port 所做的方法?
我搜索了一下,发现可以使用 udp traceroute,但是它使用 UDP 端口号 33434 上的探测,而目标服务器 IP 只监听/响应几个端口(20112、20113、20143、20156、20157、20164、20168、20175)。
所以我尝试这样做:
using (UdpClient udpClient = new UdpClient())
{
udpClient.Client.ReceiveTimeout = 3000;
for (short ttl = 1; ttl <= maxHops; ttl++)
{
string message = $"Traceroute[{ttl}]: ";
// Set the TTL option for the UDP socket
udpClient.Client.Ttl = ttl;
// Send a UDP packet to the target
udpClient.Send(new byte[1], 1, targetIp, targetPort);
message += $"UDP packet sent to {targetIp}:{targetPort}";
try
{
// Receive response from the target or an intermediate router
UdpReceiveResult result = await udpClient.ReceiveAsync();
IPAddress senderIp = result.RemoteEndPoint.Address;
if (senderIp.Equals(targetIp))
{
targetReached = true;
message += " - Target reached";
}
else
{
message += $" - Received response from {senderIp}";
}
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut)
{
message += " - Timeout";
}
else
{
message += $" - Error: {ex.Message}";
}
}
catch (Exception ex)
{
message += $" - Error: {ex.Message}";
}
if (targetReached)
{
break;
}
}
}
然而这里的问题是,一旦我设置udpClient.Client.Ttl = ttl;
它就不会再出现任何问题,UdpReceiveResult result = await udpClient.ReceiveAsync();
但如果我注释掉 TTL 它就可以正常工作。
所以现在我陷入困境,想知道是否还有其他可能的方法来跟踪 IP 路由?
无论哪种环境,linux、c#、python、powershell 我都可以,只是为了了解一下。
答案1
Traceroute 探测不需要服务器打开任何内容,因为它们的目的是触发来自中间的路由器,而不是最终主机;它们实际上从未到达最终主机。探测的实际类型并不重要;它们都会导致相同类型的答复。
但即使探测是 UDP,traceroute 探测的回复也不是 UDP 数据包,也不会通过 Receive() 传送 - 相反,你总是会得到一个 ICMPTTL Exceeded
错误数据包,这可能会被报告为异常或可能需要一些特殊的套接字选项。
(上述情况的唯一例外是“最终”探测,其 TTL 足够大,可以真正到达主机。如果主机没有响应,则跟踪将在该点挂起,但您应该为这种情况设置超时,因为中间路由器还可以不回应。