I've been trying to traceroute the Server IP for the Game Planetside2 since many Players and myself have high latency issues lately and wondered at which node those issues occur. So I tried to use CMDs tracert and Ping which didn't work, it gave me the first few addresses but before it reaches the target IP it only returns * * *, so it seems like the Server has some kind of Firewall protection against it.
Instead someone suggested me to use Linux traceroute which I did and using the UDP traceroute command together with the port of the Server IP works fine "traceroute -U -p 20105 69.174.216.21".
Here is how it looks like:
> 1 Desktop (my ip) 0.340 ms
> 2 router (router ip) 3.305 ms
> 3 isp (isp ip) 8.955 ms
> 4 62.214.42.189 (62.214.42.189) 10.675 ms
> 5 62.67.18.94 (62.67.18.94) 15.491 ms
> 6 * * *
> 7 * * *
> 8 * * *
> 9 * * *
> 10 8.227.56.190 (8.227.56.190) 99.620 ms
> 11 69.174.217.5 (69.174.217.5) 98.522 ms
> 12 69.174.216.21 (69.174.216.21) 103.844 ms
Since not everyone has Linux and doesn't know how to install it on Windows, I want to code a C# version which I can give out to the community, so they can check their connections themselves.
I've been trying for a day now but no matter what I do, I fail at a certain thing and here is the issue:
If I use code to use ICMP it works for the first 5 tls (nodes) but then I only get * * * again and it doesn't find the final IP. How it looks like (ICMP):
1 Desktop IP TtlExpired
2 Router IP TtlExpired
3 ISP IP TtlExpired
4 62.214.42.189 TtlExpired
5 62.67.18.94 TtlExpired
6 failed after 3 attempts.
7 failed after 3 attempts.
8 failed after 3 attempts.
9 failed after 3 attempts.
10 8.227.56.190 DestinationNetworkUnreachable
11 failed after 3 attempts.
12 failed after 3 attempts.
If I use code to use UDP instead for the first 6 nodes I get a "SocketException / AggregateException: The connection was terminated due to keepalive activities because an error was detected during the process" and only for the final IP I get the IP:
Traceroute[0]: - Keepalive blocked
Traceroute[1]: - Keepalive blocked
Traceroute[2]: - Keepalive blocked
Traceroute[3]: - Keepalive blocked
Traceroute[4]: - Keepalive blocked
Traceroute[5]: - No response received
Traceroute[6]: - No response received
Traceroute[7]: - No response received
Traceroute[8]: - No response received
Traceroute[9]: - No response received
Traceroute[10]: - Keepalive blocked
Traceroute[11]: - Keepalive blocked
Traceroute[11]: 69.174.216.21 - Target reached
But since it says "connection was terminated" it means there was a connection for at least 1 millisecond? So I wonder If I can get the node IP of from that terminated connection somehow then, but I don't know how to code it?
I also tried TCP but there everything failed.
So now I wonder, how does Linux's traceroute UDP code work, how is it able to get all the IPs? I already tried all of the examples here: TraceRoute and Ping in C# but none of those worked for me in this case.
I've read somewhere about "a raw-socket to listen for incoming ICMP TIME_EXCEEDED" but I'm not sure if that would give me the IP and how to do it. What am I doing wrong, maybe someone could lead me into a right direction with my code?
For ICMP:
var limit = 15;
var buffer = new byte[32];
var pingOpts = new PingOptions(1, true);
var ping = new Ping();
PingReply result = null;
do
{
int retries = 0;
pingOpts = new PingOptions(pingOpts.Ttl + 1, pingOpts.DontFragment);
while (retries < 3)
{
result = ping.Send(ipAddress, 1000, buffer, pingOpts);
if (result.Status != IPStatus.TimedOut)
{
yield return result;
break;
}
retries++;
}
if (retries == 3)
{
Console.WriteLine($"TTL {pingOpts.Ttl} failed after 3 attempts.");
}
}
while (result.Status != IPStatus.Success && pingOpts.Ttl < limit);
For UDP:
for (short ttl = 0; ttl <= 15; ttl++)
{
string message = $"Traceroute[{ttl}]: ";
try
{
using (UdpClient udpClient = new UdpClient())
{
udpClient.Client.ReceiveTimeout = 3000;
udpClient.Client.Ttl = ttl;
udpClient.DontFragment = true;
udpClient.Send(new byte[1], 1, ipAddress, targetPort);
Task<UdpReceiveResult> receiveTask = udpClient.ReceiveAsync();
if (await Task.WhenAny(receiveTask, Task.Delay(3000)) == receiveTask)
{
UdpReceiveResult result = receiveTask.Result; //crashes here because of keep-alive smth
IPAddress senderIp = result.RemoteEndPoint.Address;
if (senderIp.Equals(IPAddress.Parse(ipAddress)))
{
Console.WriteLine(message + ipAddress.ToString() + " - Target reached");
}
else
{
Console.WriteLine(message + $" - Received response from {senderIp}");
}
}
else
{
Console.WriteLine(message + $" - No response received");
}
}
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut)
{
Console.WriteLine(message + $" - No response received");
}
}
catch (System.AggregateException ex)
{
Console.WriteLine(message + $" - Keepalive blocked");
}
}