Трассировка маршрута с использованием UDP вместо ICMP?

Трассировка маршрута с использованием UDP вместо ICMP?

Я играю в игру под названием «Planetside 2», и вот уже несколько дней у многих пользователей, включая меня, возникают проблемы с высоким пингом на определенном сервере, в то время как у других их нет.

Поэтому я хотел попробовать трассировку/пинг IP-адреса сервера, чтобы выяснить, какой узел сервера вызывает проблемы с высоким пингом.

Однако, похоже, что у сервера есть какой-то брандмауэр, который защищает себя от пинга по ICMP. Всякий раз, когда я использую "ping 69.174.216.23" (IP-адрес публичен в Google, поэтому я могу поделиться им здесь), я получаю ответ о тайм-ауте.

Поэтому я использовал Wireshark, чтобы выяснить, как игровой клиент взаимодействует с сервером, и обнаружил, что он использует UDP для пинга 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)

Итак, поскольку я не могу выполнить трассировку или пинг IP-адреса сервера с помощью ICMP, мне интересно, есть ли другой возможный способ, например, использовать подход, который я использовал с udp ip:port?

Я немного поискал и обнаружил, что можно использовать udp traceroute, но он использует свой зонд на порту UDP 33434, а поскольку IP-адрес сервера Targets прослушивает/отвечает только на несколько портов (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;
        }
    }
}

Однако проблема в том, что как только я устанавливаю TTL, udpClient.Client.Ttl = ttl;он больше не появляется, UdpReceiveResult result = await udpClient.ReceiveAsync();но если я закомментирую TTL, то все работает нормально.

Теперь я в тупике и задаюсь вопросом, есть ли другой возможный способ трассировки IP-адреса?

Неважно, какая среда: Linux, C#, Python, PowerShell, меня это вполне устроит, просто чтобы иметь представление.

решение1

Зонды Traceroute не требуют, чтобы на сервере было что-либо открыто, поскольку их цель — инициировать ответы отсредниймаршрутизаторов, а не с конечного хоста; они никогда не достигают конечного хоста. Фактический тип зонда не имеет значения; все они приводят к одному и тому же виду ответа.

Но даже если зонд был UDP, ответ зондов traceroute не является пакетом UDP и не будет доставлен через Receive() — вместо этого вы всегда получите ICMPTTL Exceeded ошибкапакет, который может быть сообщен как исключение или может потребовать какой-то специальной опции сокета.

(Единственным исключением из вышесказанного является «финальный» зонд, который имеет достаточно большое значение TTL, чтобы он действительно достиг хоста. Если хост не отвечает, то трассировка зависнет на этом этапе, но у вас должны быть тайм-ауты для этой ситуации, поскольку промежуточные маршрутизаторытакжеразрешено не отвечать.)

Связанный контент