
Я играю в игру под названием «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, чтобы он действительно достиг хоста. Если хост не отвечает, то трассировка зависнет на этом этапе, но у вас должны быть тайм-ауты для этой ситуации, поскольку промежуточные маршрутизаторытакжеразрешено не отвечать.)