跟踪路由使用 UDP 而不是 ICMP?

跟踪路由使用 UDP 而不是 ICMP?

我正在玩一款名为“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 足够大,可以真正到达主机。如果主机没有响应,则跟踪将在该点挂起,但您应该为这种情况设置超时,因为中间路由器可以不回应。

相关内容