All we know that PC can have one or more network interfaces. Each network interface can have one or two (maybe more) ip addresses. The problem is how to determine which ip address will be used to communicate with remote host.
I know how to get network interface using next code (thank's guys from pinvoke.net):
private static NetworkInterface GetNetworkInterfaceByIndex(uint index)
{
// Search in all network interfaces that support IPv4.
NetworkInterface ipv4Interface = (from thisInterface in NetworkInterface.GetAllNetworkInterfaces()
where thisInterface.Supports(NetworkInterfaceComponent.IPv4)
let ipv4Properties = thisInterface.GetIPProperties().GetIPv4Properties()
where ipv4Properties != null && ipv4Properties.Index == index
select thisInterface).SingleOrDefault();
if (ipv4Interface != null)
return ipv4Interface;
// Search in all network interfaces that support IPv6.
NetworkInterface ipv6Interface = (from thisInterface in NetworkInterface.GetAllNetworkInterfaces()
where thisInterface.Supports(NetworkInterfaceComponent.IPv6)
let ipv6Properties = thisInterface.GetIPProperties().GetIPv6Properties()
where ipv6Properties != null && ipv6Properties.Index == index
select thisInterface).SingleOrDefault();
return ipv6Interface;
}
[DllImport("iphlpapi.dll", SetLastError = true)]
static extern int GetBestInterface(uint DestAddr, out uint BestIfIndex);
static void IpAddressLogTest()
{
Console.Write("Enter IP address to choose interface: ");
IPAddress addr;
IPAddress.TryParse(Console.ReadLine(), out addr);
uint bestintf;
var res = GetBestInterface(BitConverter.ToUInt32(addr.GetAddressBytes(), 0), out bestintf);
NetworkInterface interfaceInfo = GetNetworkInterfaceByIndex(bestintf);
foreach (var a in interfaceInfo.GetIPProperties().UnicastAddresses)
if (a.Address.AddressFamily == AddressFamily.InterNetwork)
Console.WriteLine(a.Address.ToString());
Console.ReadLine();
}
This code works perfectly and i know what interface will be used to communicate with host. But interface can have two ip addresses in different networks.
How in that case to choose right ip address?
UPD1. Example of such settings:
Related
when using System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName())to get IP addresses and
private System.Net.NetworkInformation.PhysicalAddress GetMacAddress()
{
foreach (System.Net.NetworkInformation.NetworkInterface nic in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces())
{
// Only consider Ethernet network interfaces
if (nic.NetworkInterfaceType == System.Net.NetworkInformation.NetworkInterfaceType.Ethernet &&
nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up)
{
return nic.GetPhysicalAddress();
}
}
return null;
}
to get the MAC adddress, I get all addresses. Is there a way to get only the adapter and IP that actually connects to the net?
With above calls, I also get IP's and MAC's belonging to virtual adapters, such as the created by VMWare.
Regards
Jaime
As a good approach, I am looking for the NIC that has a gateway set. This works in my case:
private static IEnumerable<System.Net.NetworkInformation.NetworkInterface> GetAllNetworkInterfaces(IEnumerable<System.Net.NetworkInformation.NetworkInterfaceType> excludeTypes)
{
var all = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces().Where(nic => nic.GetIPProperties().GatewayAddresses.Any() && nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up);
var exclude = all.Where(i => excludeTypes.Contains(i.NetworkInterfaceType));
return all.Except(exclude);
}
And then, use it like this:
var nic = GetAllNetworkInterfaces(new[] { System.Net.NetworkInformation.NetworkInterfaceType.Tunnel, System.Net.NetworkInformation.NetworkInterfaceType.Loopback });
txtRegistro.AppendText($"Local IP -> {string.Join(", ", nic.SelectMany(n => n.GetIPProperties().UnicastAddresses).Where(i => i.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).Select(i => i.Address.ToString()))}\r\n");
txtRegistro.AppendText($"MAC Address -> {string.Join(", ", nic.Select(a => string.Join(":", a.GetPhysicalAddress().GetAddressBytes().Select(b => b.ToString("X2")))))}\r\n\r\n");
With above code, I am getting which NIC has a connection to a network (LAN or WAN) as long as the connected router provides a gateway.
Regards
Jaime
My adapter network interface have 5:
{"Id":"{FD94887A-FEEB-4F0B-AE11-D3A36137976B}","Name":"Ethernet","Description":"Intel(R) Ethernet Connection I217-LM","NetworkInterfaceType":6,"OperationalStatus":2,"Speed":-1,"IsReceiveOnly":false,"SupportsMulticast":true}
{"Id":"{765A365A-6D0B-4ACB-BCC8-779F481DC5D5}","Name":"Local Area Connection* 13","Description":"Microsoft Wi-Fi Direct Virtual Adapter #5","NetworkInterfaceType":71,"OperationalStatus":2,"Speed":-1,"IsReceiveOnly":false,"SupportsMulticast":true}
{"Id":"{D888C03B-82F1-4BBB-AB99-185F21B62159}","Name":"Local Area Connection* 14","Description":"Microsoft Wi-Fi Direct Virtual Adapter #6","NetworkInterfaceType":71,"OperationalStatus":2,"Speed":-1,"IsReceiveOnly":false,"SupportsMulticast":true}
{"Id":"{56ECAAAF-8916-4358-A8DB-FB6E7448133D}","Name":"Wi-Fi 4","Description":"Intel(R) Centrino(R) Ultimate-N 6300 AGN","NetworkInterfaceType":71,"OperationalStatus":1,"Speed":135000000,"IsReceiveOnly":false,"SupportsMulticast":true}
{"Id":"{80377EDA-E86D-11E8-BA87-806E6F6E6963}","Name":"Loopback Pseudo-Interface 1","Description":"Software Loopback Interface 1","NetworkInterfaceType":24,"OperationalStatus":1,"Speed":1073741824,"IsReceiveOnly":false,"SupportsMulticast":true}
There are 3 attributes we need to care about: NetworkInterfaceType, OperationalStatus, Speed
This is my code:
private PhysicalAddress GetMacAddress()
{
var allowNetworkInterfaceType = new[] { NetworkInterfaceType.Ethernet , NetworkInterfaceType.Wireless80211 , NetworkInterfaceType.GigabitEthernet };
var networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(x=>x.OperationalStatus == OperationalStatus.Up && allowNetworkInterfaceType.Contains(x.NetworkInterfaceType) && x.Speed > 0);
return networkInterface?.GetPhysicalAddress();
}
I try type ipconfig on cmd.exe and ip address ="172.24.70.68"
But If i get IP of this PC, it return IP: 127.0.0.1
This my code get IP Address:
IPAddress ip = null;
IPAddress mask = null;
//++**********************************
// Get IP
//--**********************************
strHostName = Dns.GetHostName();
IPHostEntry iphe = Dns.GetHostEntry(strHostName);
foreach (IPAddress ipheal in iphe.AddressList)
{
if (ipheal.AddressFamily ==AddressFamily.InterNetwork)
{
ip = ipheal;
break;
}
}
Why IP Address return value 127.0.0.1?
Some other PCs, it getting IP is ok.
Try not to get the address via DNS, which may be deceiving or simply not working if for example there are no DNS records for the computer, but via the adapter settings, which is essentially the same ipconfig does.
You can get all of the adapters with NetworkInterface.GetAllNetworkInterfaces(). The NetworkInterfaceType property let's you filter for Ethernet adapters as well as exclude the loop back adapter. You can also filter only for adapters in a particular status, e.g. up, with the OperationalStatus property.
You can then loop through all the unicast addresses of the adapter and pick one of the IPv4 addresses from it, for example the first one encountered. Of course, if you have more adapters or addresses on one adapter this might still not be the one you're looking for. In that case you need to define how to recognize the one you want and implement that accordingly.
IPAddress ip = null;
IPAddress mask = null;
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
{
bool found = false;
if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet
&& networkInterface.OperationalStatus == OperationalStatus.Up
&& networkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback)
{
foreach (UnicastIPAddressInformation unicastIPAddressInformation in networkInterface.GetIPProperties().UnicastAddresses)
{
if (unicastIPAddressInformation.Address.AddressFamily == AddressFamily.InterNetwork)
{
ip = unicastIPAddressInformation.Address;
mask = unicastIPAddressInformation.IPv4Mask;
found = true;
break;
}
}
}
if (found)
{
break;
}
}
You need to use forwarder Header
.net core example
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
});
I need to get the IP address of a Wi-Fi module, running a TCP server. The application will open the WiFi connections settings page to allow the user to connect to the Wi-Fi module's created network (requiring the password to be entered)- see attached picture. The server (Wi-FI module) IP address is 172.1.4.155 (for example) but when I try to get the IP address in Xamarin.Forms using GetLocalIPAddress() (attached below), the address it returns is the local IP address of the device (Phone)- 172.1.4.55 (for example). I need to be able to get the IP address programmatically without a user input in an Application.
Is there any way to get the IP address of the (external) non-device specific IP address? I assume the returned IP address of the phone is the DHCP assigned IP address. I need to get the server IP address as it is essential to establish a TCP socket connection between the phone and the WiFi module. I have been trying to look for a solution without any success for a few days now so any help/suggestions or examples will be greatly appreciated.
The code below is the GetLocalIPAddress() function to get the IP address.
public static string GetLocalIPAddress()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
//return "";
}
//throw new Exception("Local IP Address Not Found!");
return "None";
}
How to Read IP Address in XAMARIN Form, i have Created the DependencyServices in both IOS and Android projects and getting a proper IP address. Below is code to get IP address.
In PCL Project
public interface IIPAddressManager
{
String GetIPAddress();
}
In IOS Project
[assembly: Dependency(typeof(YourAppNamespace.iOSUnified.iOS.DependencyServices.IPAddressManager))]
namespace YourAppNamespace.iOSUnified.iOS.DependencyServices
{
class IPAddressManager : IIPAddressManager
{
public string GetIPAddress()
{
String ipAddress = "";
foreach (var netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
if (netInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
netInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
foreach (var addrInfo in netInterface.GetIPProperties().UnicastAddresses)
{
if (addrInfo.Address.AddressFamily == AddressFamily.InterNetwork)
{
ipAddress = addrInfo.Address.ToString();
}
}
}
}
return ipAddress;
}
}
}
In Android Project.
[assembly: Dependency(typeof(YourAppNamespace.Android.Android.DependencyServices.IPAddressManager))]
namespace YourAppNamespace.Android.Android.DependencyServices
{
class IPAddressManager : IIPAddressManager
{
public string GetIPAddress()
{
IPAddress[] adresses = Dns.GetHostAddresses(Dns.GetHostName());
if (adresses !=null && adresses[0] != null)
{
return adresses[0].ToString();
}
else
{
return null;
}
}
}
}
Then call a DependencyServices in UI project.
string ipaddress = DependencyService.Get<IIPAddressManager>().GetIPAddress
In my app I need to display IP addresses of each available (wifi or ethernet) adapter.
Problem is I get more then one IP address per adapter, and last one I get (per adapter) is one I'm looking for.
I dont know what for are first two (usually they are first two) IP addresses and how to get "real" IP address. I compared these two IP addresses that I get before "real" one with CMD and "ipconfig" command and they are not mentioned there, so its not default gateway, subnet mask,local Ipv6 or public IP address.
This is what my app outputs:
This is what I want:
Code I use:
foreach (NetworkInterface inf in devs)
{
if (inf.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || inf.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
foreach (UnicastIPAddressInformation address in inf.GetIPProperties().UnicastAddresses)
{
if (address.Address.AddressFamily == AddressFamily.InterNetwork)
MessageBox.Show(address.Address.ToString());
}
}
}
Here is the answer on how to get IP addresses (IPv4 and IPv6) per adapter.
NetworkInterface[] intf = NetworkInterface.GetAllNetworkInterfaces();
foreach(NetworkInterface device in intf)
{
IPAddress ipv6Address = device.GetIPProperties().UnicastAddresses[0].Address; //This will give ipv6 address of certain adapter
IPAddress ipv4Address = device.GetIPProperties().UnicastAddresses[1].Address; //This will give ipv4 address of certain adapter
}
I'm writing a program that shows the user their IP address, Subnet mask and Default gateway. I can get the first two, but for the last one, this is what I turned up:
GatewayIPAddressInformationCollection gwc =
System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0].GetIPProperties().GatewayAddresses;
That, of course, returns a collection of GatewayIPAddressInformation. So, if a computer has multiple gateways, how can I determine which is the default gateway?
In practice, I've only ever seen this collection contain a single entry, but since it's implemented as a collection, it stands to reason that some computers contain multiple gateways, none of which are marked as "Default". So is there a way to determine the default or is it all just guesswork?
It will probably be the first valid and enabled gateway address of the first enabled network interface:
public static IPAddress GetDefaultGateway()
{
return NetworkInterface
.GetAllNetworkInterfaces()
.Where(n => n.OperationalStatus == OperationalStatus.Up)
.Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.SelectMany(n => n.GetIPProperties()?.GatewayAddresses)
.Select(g => g?.Address)
.Where(a => a != null)
// .Where(a => a.AddressFamily == AddressFamily.InterNetwork)
// .Where(a => Array.FindIndex(a.GetAddressBytes(), b => b != 0) >= 0)
.FirstOrDefault();
}
I've also added some further commented checks which have been pointed out as useful by other people here. You can check the AddressFamily one to distinguish between IPv4 and IPv6. The latter one can be used to filter out 0.0.0.0 addresses.
The above solution will give you a valid/connected interface, and is good enough for 99% of situations. That said, if you have multiple valid interfaces that traffic can be routed through, and you need to be 100% accurate, the way to do this uses GetBestInterface to find an interface for routing to a specific IP address. This additionally handles the case where you might have a specific address range routed through a different adapter (e.g. 10.*.*.* going through a VPN, everything else going to your router)
[DllImport("iphlpapi.dll", CharSet = CharSet.Auto)]
private static extern int GetBestInterface(UInt32 destAddr, out UInt32 bestIfIndex);
public static IPAddress GetGatewayForDestination(IPAddress destinationAddress)
{
UInt32 destaddr = BitConverter.ToUInt32(destinationAddress.GetAddressBytes(), 0);
uint interfaceIndex;
int result = GetBestInterface(destaddr, out interfaceIndex);
if (result != 0)
throw new Win32Exception(result);
foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
{
var niprops = ni.GetIPProperties();
if (niprops == null)
continue;
var gateway = niprops.GatewayAddresses?.FirstOrDefault()?.Address;
if (gateway == null)
continue;
if (ni.Supports(NetworkInterfaceComponent.IPv4))
{
var v4props = niprops.GetIPv4Properties();
if (v4props == null)
continue;
if (v4props.Index == interfaceIndex)
return gateway;
}
if (ni.Supports(NetworkInterfaceComponent.IPv6))
{
var v6props = niprops.GetIPv6Properties();
if (v6props == null)
continue;
if (v6props.Index == interfaceIndex)
return gateway;
}
}
return null;
}
These two examples could be wrapped up into a helper class and used in the appropriate cases: that you do, or do not have a destination address in mind already.
The first IP address returned by traceroute command will be the gateway .You can use this fact for getting gateway.A nice implementation of tracerout can be found here:
TraceRoute and Ping in C#
according to #midspace's comment on #caesay's answer this is a better answer:
public static IPAddress GetDefaultGateway()
{
var gateway_address = NetworkInterface.GetAllNetworkInterfaces()
.Where(e => e.OperationalStatus == OperationalStatus.Up)
.SelectMany(e => e.GetIPProperties().GatewayAddresses)
.FirstOrDefault();
if (gateway_address == null) return null;
return gateway_address.Address;
}
I'm warning that it's not a complete solution, if your'e looking for the main interface responsible for the internet access, you should combine other approaches like using win32 API GetBestInterface to find the best interface to connect to a destination address.
you can find example usage here: http://www.pinvoke.net/default.aspx/iphlpapi.getbestinterface
I've just come across this and will be using the following code - basically it looks for interfaces that aren't loopback and are up and have gateways and unicast addresses. From the interface I then get a non transient IPV4 address.
public static class NetworkInterfaces
{
public static NetworkInterface GetDefaultInterface()
{
var interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
foreach (var intf in interfaces)
{
if (intf.OperationalStatus != OperationalStatus.Up)
{
continue;
}
if (intf.NetworkInterfaceType == NetworkInterfaceType.Loopback)
{
continue;
}
var properties = intf.GetIPProperties();
if (properties == null)
{
continue;
}
var gateways = properties.GatewayAddresses;
if ((gateways == null) || (gateways.Count == 0))
{
continue;
}
var addresses = properties.UnicastAddresses;
if ((addresses == null) || (addresses.Count == 0))
{
continue;
}
return intf;
}
return null;
}
public static IPAddress GetDefaultIPV4Address(NetworkInterface intf)
{
if (intf == null)
{
return null;
}
foreach (var address in intf.GetIPProperties().UnicastAddresses)
{
if (address.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
if (address.IsTransient)
{
continue;
}
return address.Address;
}
return null;
}
}
I know this is a slightly older question but, I had just come upon the need to retrieve the IPV4 address of the local gateway. The accepted answer doesn't quite fit the bill when it comes to my own system so, I modified it to suite and I'm sure others will be able to use this solution, too.
Since I don't yet have enough rep to comment, I'm forced to add this as a "question":
public static IPAddress GetDefaultGateway()
{
IPAddress result = null;
var cards = NetworkInterface.GetAllNetworkInterfaces().ToList();
if (cards.Any())
{
foreach (var card in cards)
{
var props = card.GetIPProperties();
if (props == null)
continue;
var gateways = props.GatewayAddresses;
if (!gateways.Any())
continue;
var gateway =
gateways.FirstOrDefault(g => g.Address.AddressFamily.ToString() == "InterNetwork");
if (gateway == null)
continue;
result = gateway.Address;
break;
};
}
return result;
}
Been looking for one weird trick to determine the local IP address?
Yet do it very robustly vs. the earlier methods?
[See end for response to #caesay]
This may be what you are looking for.
using (var s = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp))
{
s.Bind( new System.Net.IPEndPoint(System.Net.IPAddress.Any,0));
s.Connect("google.com",0);
var ipaddr = s.LocalEndPoint as System.Net.IPEndPoint;
var addr = ipaddr.Address.ToString();
Console.WriteLine(addr);
}
That will create a UDP socket, but will not send data on it.
You can then see what local interface and address the socket was bound to.
You must supply an IP address or hostname where I used google.com, that will
be used by the OS to determine which interface the socket will be bound to,
and what IP address you will find using this method.
For 99%+ of IP addresses or hostnames you use, you will get the interface+address to be used for traffic over the default route.
While this is a little obtuse, I suspect it is more reliable than the methods above where people use the PInvoke call and scan through the structures to see if they can find the interface.
I certainly found it more robust on my 3x double interface systems than scanning through the results of NetworkInterface.GetAllNetworkInterfaces() using heuristics to try to figure out the default interface address.
[Update/response to #caesay 2/6/2019]
#caesay Has made an excellent point here, so I have switched the sample from using UdpClient to Socket, and explicitly called Socket.Connect() after Bind(). I have also reviewed the Framework source for Connect() and LocalEndPoint, and both call their corresponding Win32 OS system call immediately without deferring or being lazy about calling into the OS. The Win32 bind page says "The application can use getsockname after calling bind to learn the address and the port that has been assigned to the socket. If the Internet address is equal to INADDR_ANY or in6addr_any, getsockname cannot necessarily supply the address until the socket is connected".
This condition is now explicitly addressed, and having reviewed the Framework source, the IP address should always be available after the Connect() call.
NetworkInterface[] allNICs = NetworkInterface.GetAllNetworkInterfaces();
foreach (var nic in allNICs)
{
var ipProp = nic.GetIPProperties();
var gwAddresses = ipProp.GatewayAddresses;
if (gwAddresses.Count > 0 &&
gwAddresses.FirstOrDefault(g => g.Address.AddressFamily == AddressFamily.InterNetwork) != null)
{
localIP = ipProp.UnicastAddresses.First(d => d.Address.AddressFamily == AddressFamily.InterNetwork).Address;
}
}
Debug.Print(localIP.ToString());
(Just after posting I noticed an earlier answer that mentioned the idea of using traceroute. I probably wouldn't have responded if I'd seen that. But I have included complete/compact code.)
Here's a different approach that finds the default gateway by using a traceroute type method. Ping an address on the internet (or other network you want to get to) with a TTL of 1, and let ping tell you what the first hop IP address was. That ought to be the gateway you're looking for.
I suppose this could go wrong if the gateway was configured not to reply to pings, but I don't think I've ever heard of a network set up that way.
Note: This routine kind-of even works if you pass it an IPV6 address. The potential issue is that it seems to return an IPV6 address with Global scope, rather than Link-Local scope. I don't have enough experience using IPV6 to know if that's good or bad. But I do know that the Windows ipconfig command displays the Link-Local IPV6 addresses of the interface gateway.
using System.Net
using System.Net.NetworkInformation
// ping internet address with ttl=1 and return address of host where ttl expired
public static IPAddress FindDefaultGateway(IPAddress netaddr = null)
{
// user can provide an ip address that exists on the network they want to connect to,
// or this routine will default to 1.1.1.1 (IP of a popular internet dns provider)
if (netaddr is null)
netaddr = IPAddress.Parse("1.1.1.1");
PingReply reply = default;
using var ping = new Ping();
var options = new PingOptions(1, true); // ttl=1, dont fragment=true
try {
// I arbitrarily used a 200ms timeout; tune as you see fit.
reply = ping.Send(netaddr, 200, new byte[0], options);
}
catch (PingException) {
System.Diagnostics.Debug.WriteLine("Gateway not available");
return default;
}
if (reply.Status != IPStatus.TtlExpired) {
System.Diagnostics.Debug.WriteLine("Gateway not available");
return default;
}
return reply.Address;
}
I think that you should iterate over this collection and show all the Gateways, since if there are many gateways to an adapter they are all considered Default to that adapter