Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# Know with which IP we use to communicate with another IP?

With a homemade discovery tools, I've discovered a list of services that I'm interested to.

I've their IP, service name, port, host, ... But to use them, I've to specify to the client library the IP we will be using.

Since I've several network cards, I need to detect which interface is used to communicate with the destination IP that I know, and then give this IPAddress to my library.

But how could I detected which interface IP I should use?

I tried to make some search over the internet, but I think I don't have the right keywords because I don't find anything relevant.

like image 512
J4N Avatar asked Dec 21 '22 09:12

J4N


2 Answers

I've pulled the relevant method out for you from the network library I develop for, networkComms.net:

/// <summary>
/// Determines the most appropriate local end point to contact the provided remote end point. 
/// Testing shows this method takes on average 1.6ms to return.
/// </summary>
/// <param name="remoteIPEndPoint">The remote end point</param>
/// <returns>The selected local end point</returns>
public static IPEndPoint BestLocalEndPoint(IPEndPoint remoteIPEndPoint)
{    
    Socket testSocket = new Socket(remoteIPEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
    testSocket.Connect(remoteIPEndPoint);
    return (IPEndPoint)testSocket.LocalEndPoint;
}

Once you have the correct IP and you could then iterate over NetworkInterface.GetAllNetworkInterfaces() to locate the matching adapter.

like image 165
MarcF Avatar answered Jan 23 '23 14:01

MarcF


The following works by querying the routing table. This is the same way Socket.Connect determines what local endpoint to use. Differences:

  • can't fail due to firewall
  • can't fail due to nonexistent remote endpoint
  • doesn't reserve a local port
  • faster

.

private static IPEndPoint QueryRoutingInterface(
          Socket socket,
          IPEndPoint remoteEndPoint)
{
    SocketAddress address = remoteEndPoint.Serialize();

    byte[] remoteAddrBytes = new byte[address.Size];
    for (int i = 0; i < address.Size; i++) {
        remoteAddrBytes[i] = address[i];
    }

    byte[] outBytes = new byte[remoteAddrBytes.Length];
    socket.IOControl(
                IOControlCode.RoutingInterfaceQuery, 
                remoteAddrBytes, 
                outBytes);
    for (int i = 0; i < address.Size; i++) {
        address[i] = outBytes[i];
    }

    EndPoint ep = remoteEndPoint.Create(address);
    return (IPEndPoint)ep;
}

which is used like:

IPAddress remoteIp = IPAddress.Parse("192.168.1.55");
IpEndPoint remoteEndPoint = new IPEndPoint(remoteIp, 0);
Socket socket = new Socket(
                      AddressFamily.InterNetwork, 
                      SocketType.Dgram, 
                      ProtocolType.Udp);
IPEndPoint localEndPoint = QueryRoutingInterface(socket, remoteEndPoint );
Console.WriteLine("Local EndPoint is: {0}", localEndPoint);

(source code copied from here)

Please note that although one is specifying an IpEndPoint with a port, the port is irrelevant. Also, the returned IpEndPoint.Port is always 0.

like image 36
BatteryBackupUnit Avatar answered Jan 23 '23 13:01

BatteryBackupUnit