Search code examples
c#socketstcp

Matching TCP connections between TcpClient and TcpConnectionInformation[]


I have a TcpClient with Client.LocalEndPoint and Client.RemoteEndPoint. The connection is active (to a local TCP server).

I gather the list of TCP connections via:

IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] connections = properties.GetActiveTcpConnections();

When I try to find the connection within connections, I'm having a difficult time matching because the value/contents of Client.LocalEndPoint and Client.RemoteEndPoint are of a different form than those in TcpConnectionInformation.

e.g.

Console.WriteLine(client.Client.LocalEndPoint.ToString());
// [::ffff:127.0.0.1]:55853

and

foreach (var conn in connections)
{
  Console.WriteLine(conn.LocalEndPoint.ToString() + " to " + conn.RemoteEndPoint.ToString() + ": " + conn.State.ToString());
  // 127.0.0.1:55853 to 127.0.0.1:8000: Established
}

As a result, this returns null:

var state = connections.FirstOrDefault(x =>
                x.LocalEndPoint.Equals(client.Client.LocalEndPoint)
                && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint));

It appears that the TcpClient is reporting a hybrid IPv6+IPv4 address, whereas TcpConnectionInformation is reporting only the IPv4 address.

Is there an effective cross-platform way of comparing to identify the connection information?


Solution

  • The problem is that since Windows is now fully dual-stacked, all IP addresses are represented as Ipv4-Mapped-To-IPv6 addresses (RFC4291). These are not IPv6 addresses and cannot be routed as IPv6, they are simply used to represent IPv4 addresses on an IPv6 machine.

    Quite why TcpConnectionInformation does not also show addresses this way is unclear.

    To convert them, there is a function to convert back to standard IPv4:

    var local = (client.Client.LocalEndPoint as IPEndpoint)?.Address;
    if (local?.IsIPv4MappedToIPv6 ?? false)
        local = local.MapToIPv4();
    
    var remote = (client.Client.RemoteEndPoint as IPEndPoint)?.Address;
    if (remote?.IsIPv4MappedToIPv6 ?? false)
        remote = remote.MapToIPv4();
    

    You can also convert the other way if you want.