Reliable method to get machine's MAC address in C# - c#

I need a way to get a machine's MAC address, regardless of the OS it is running, by using C#.
The application will need to work on XP/Vista/Win7 32bit and 64bit, as well as on those OSs but with a foreign language default. Also, many of the C# commands and OS queries don't work across all the OSs.
Do you have any ideas?
I have been scraping the output of ipconfig /all but this is terribly unreliable as the output format differs on every machine.

Cleaner solution
var macAddr =
(
from nic in NetworkInterface.GetAllNetworkInterfaces()
where nic.OperationalStatus == OperationalStatus.Up
select nic.GetPhysicalAddress().ToString()
).FirstOrDefault();
Or:
String firstMacAddress = NetworkInterface
.GetAllNetworkInterfaces()
.Where( nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback )
.Select( nic => nic.GetPhysicalAddress().ToString() )
.FirstOrDefault();

Here's some C# code which returns the MAC address of the first operational network interface. Assuming the NetworkInterface assembly is implemented in the runtime (i.e. Mono) used on other operating systems then this would work on other operating systems.
New version: returns the NIC with the fastest speed that also has a valid MAC address.
/// <summary>
/// Finds the MAC address of the NIC with maximum speed.
/// </summary>
/// <returns>The MAC address.</returns>
private string GetMacAddress()
{
const int MIN_MAC_ADDR_LENGTH = 12;
string macAddress = string.Empty;
long maxSpeed = -1;
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
log.Debug(
"Found MAC Address: " + nic.GetPhysicalAddress() +
" Type: " + nic.NetworkInterfaceType);
string tempMac = nic.GetPhysicalAddress().ToString();
if (nic.Speed > maxSpeed &&
!string.IsNullOrEmpty(tempMac) &&
tempMac.Length >= MIN_MAC_ADDR_LENGTH)
{
log.Debug("New Max Speed = " + nic.Speed + ", MAC: " + tempMac);
maxSpeed = nic.Speed;
macAddress = tempMac;
}
}
return macAddress;
}
Original Version: just returns the first one.
/// <summary>
/// Finds the MAC address of the first operation NIC found.
/// </summary>
/// <returns>The MAC address.</returns>
private string GetMacAddress()
{
string macAddresses = string.Empty;
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == OperationalStatus.Up)
{
macAddresses += nic.GetPhysicalAddress().ToString();
break;
}
}
return macAddresses;
}
The only thing I don't like about this approach is if you have like a Nortel Packet Miniport or some type of VPN connection it has the potential of being chosen. As far as I can tell, there is no way to distinguish an actual physical device's MAC from some type of virtual network interface.

IMHO returning first mac address isn't good idea, especially when virtual machines are hosted. Therefore i check send/received bytes sum and select most used connection, that is not perfect, but should be correct 9/10 times.
public string GetDefaultMacAddress()
{
Dictionary<string, long> macAddresses = new Dictionary<string, long>();
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == OperationalStatus.Up)
macAddresses[nic.GetPhysicalAddress().ToString()] = nic.GetIPStatistics().BytesSent + nic.GetIPStatistics().BytesReceived;
}
long maxValue = 0;
string mac = "";
foreach(KeyValuePair<string, long> pair in macAddresses)
{
if (pair.Value > maxValue)
{
mac = pair.Key;
maxValue = pair.Value;
}
}
return mac;
}

The MACAddress property of the Win32_NetworkAdapterConfiguration WMI class can provide you with an adapter's MAC address. (System.Management Namespace)
MACAddress
Data type: string
Access type: Read-only
Media Access Control (MAC) address of the network adapter. A MAC address is assigned by the manufacturer to uniquely identify the network adapter.
Example: "00:80:C7:8F:6C:96"
If you're not familiar with the WMI API (Windows Management Instrumentation), there's a good overview here for .NET apps.
WMI is available across all version of windows with the .Net runtime.
Here's a code example:
System.Management.ManagementClass mc = default(System.Management.ManagementClass);
ManagementObject mo = default(ManagementObject);
mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
foreach (var mo in moc) {
if (mo.Item("IPEnabled") == true) {
Adapter.Items.Add("MAC " + mo.Item("MacAddress").ToString());
}
}

WMI is the best solution if the machine you are connecting to is a windows machine, but if you are looking at a linux, mac, or other type of network adapter, then you will need to use something else. Here are some options:
Use the DOS command nbtstat -a . Create a process, call this command, parse the output.
First Ping the IP to make sure your NIC caches the command in it's ARP table, then use the DOS command arp -a . Parse the output of the process like in option 1.
Use a dreaded unmanaged call to sendarp in the iphlpapi.dll
Heres a sample of item #3. This seems to be the best option if WMI isn't a viable solution:
using System.Runtime.InteropServices;
...
[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);
...
private string GetMacUsingARP(string IPAddr)
{
IPAddress IP = IPAddress.Parse(IPAddr);
byte[] macAddr = new byte[6];
uint macAddrLen = (uint)macAddr.Length;
if (SendARP((int)IP.Address, 0, macAddr, ref macAddrLen) != 0)
throw new Exception("ARP command failed");
string[] str = new string[(int)macAddrLen];
for (int i = 0; i < macAddrLen; i++)
str[i] = macAddr[i].ToString("x2");
return string.Join(":", str);
}
To give credit where it is due, this is the basis for that code:
http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#

We use WMI to get the mac address of the interface with the lowest metric, e.g. the interface windows will prefer to use, like this:
public static string GetMACAddress()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
string mac = (from o in objects orderby o["IPConnectionMetric"] select o["MACAddress"].ToString()).FirstOrDefault();
return mac;
}
Or in Silverlight (needs elevated trust):
public static string GetMACAddress()
{
string mac = null;
if ((Application.Current.IsRunningOutOfBrowser) && (Application.Current.HasElevatedPermissions) && (AutomationFactory.IsAvailable))
{
dynamic sWbemLocator = AutomationFactory.CreateObject("WbemScripting.SWBemLocator");
dynamic sWbemServices = sWbemLocator.ConnectServer(".");
sWbemServices.Security_.ImpersonationLevel = 3; //impersonate
string query = "SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true";
dynamic results = sWbemServices.ExecQuery(query);
int mtu = int.MaxValue;
foreach (dynamic result in results)
{
if (result.IPConnectionMetric < mtu)
{
mtu = result.IPConnectionMetric;
mac = result.MACAddress;
}
}
}
return mac;
}

This method will determine the MAC address of the Network Interface used to connect to the specified url and port.
All the answers here are not capable of achieving this goal.
I wrote this answer years ago (in 2014). So I decided to give it a little "face lift". Please look at the updates section
/// <summary>
/// Get the MAC of the Netowrk Interface used to connect to the specified url.
/// </summary>
/// <param name="allowedURL">URL to connect to.</param>
/// <param name="port">The port to use. Default is 80.</param>
/// <returns></returns>
private static PhysicalAddress GetCurrentMAC(string allowedURL, int port = 80)
{
//create tcp client
var client = new TcpClient();
//start connection
client.Client.Connect(new IPEndPoint(Dns.GetHostAddresses(allowedURL)[0], port));
//wai while connection is established
while(!client.Connected)
{
Thread.Sleep(500);
}
//get the ip address from the connected endpoint
var ipAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address;
//if the ip is ipv4 mapped to ipv6 then convert to ipv4
if(ipAddress.IsIPv4MappedToIPv6)
ipAddress = ipAddress.MapToIPv4();
Debug.WriteLine(ipAddress);
//disconnect the client and free the socket
client.Client.Disconnect(false);
//this will dispose the client and close the connection if needed
client.Close();
var allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
//return early if no network interfaces found
if(!(allNetworkInterfaces?.Length > 0))
return null;
foreach(var networkInterface in allNetworkInterfaces)
{
//get the unicast address of the network interface
var unicastAddresses = networkInterface.GetIPProperties().UnicastAddresses;
//skip if no unicast address found
if(!(unicastAddresses?.Count > 0))
continue;
//compare the unicast addresses to see
//if any match the ip address used to connect over the network
for(var i = 0; i < unicastAddresses.Count; i++)
{
var unicastAddress = unicastAddresses[i];
//this is unlikely but if it is null just skip
if(unicastAddress.Address == null)
continue;
var ipAddressToCompare = unicastAddress.Address;
Debug.WriteLine(ipAddressToCompare);
//if the ip is ipv4 mapped to ipv6 then convert to ipv4
if(ipAddressToCompare.IsIPv4MappedToIPv6)
ipAddressToCompare = ipAddressToCompare.MapToIPv4();
Debug.WriteLine(ipAddressToCompare);
//skip if the ip does not match
if(!ipAddressToCompare.Equals(ipAddress))
continue;
//return the mac address if the ip matches
return networkInterface.GetPhysicalAddress();
}
}
//not found so return null
return null;
}
To call it you need to pass a URL to connect to like this:
var mac = GetCurrentMAC("www.google.com");
You can also specify a port number. If not specified default is 80.
UPDATES:
2020
Added comments to explain the code.
Corrected to be used with newer
operating systems that use IPV4 mapped to IPV6 ( like windows 10 ).
Reduced nesting.
Upgraded the code use "var".

public static PhysicalAddress GetMacAddress()
{
var myInterfaceAddress = NetworkInterface.GetAllNetworkInterfaces()
.Where(n => n.OperationalStatus == OperationalStatus.Up && n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.OrderByDescending(n => n.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.Select(n => n.GetPhysicalAddress())
.FirstOrDefault();
return myInterfaceAddress;
}

You could go for the NIC ID:
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
if (nic.OperationalStatus == OperationalStatus.Up){
if (nic.Id == "yay!")
}
}
It's not the MAC address, but it is a unique identifier, if that's what you're looking for.

I really like AVee's solution with the lowest IP connection metric! But if a second nic with the same metric is installed, the MAC comparison could fail...
Better you store the description of the interface with the MAC. In later comparisons you can identify the right nic by this string. Here is a sample code:
public static string GetMacAndDescription()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
string mac = (from o in objects orderby o["IPConnectionMetric"] select o["MACAddress"].ToString()).FirstOrDefault();
string description = (from o in objects orderby o["IPConnectionMetric"] select o["Description"].ToString()).FirstOrDefault();
return mac + ";" + description;
}
public static string GetMacByDescription( string description)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
string mac = (from o in objects where o["Description"].ToString() == description select o["MACAddress"].ToString()).FirstOrDefault();
return mac;
}

let's say I have a TcpConnection using my local ip of 192.168.0.182. Then if I will like to know the mac address of that NIC I will call the meothod as: GetMacAddressUsedByIp("192.168.0.182")
public static string GetMacAddressUsedByIp(string ipAddress)
{
var ips = new List<string>();
string output;
try
{
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = "ipconfig";
p.StartInfo.Arguments = "/all";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
catch
{
return null;
}
// pattern to get all connections
var pattern = #"(?xis)
(?<Header>
(\r|\n) [^\r]+ : \r\n\r\n
)
(?<content>
.+? (?= ( (\r\n\r\n)|($)) )
)";
List<Match> matches = new List<Match>();
foreach (Match m in Regex.Matches(output, pattern))
matches.Add(m);
var connection = matches.Select(m => new
{
containsIp = m.Value.Contains(ipAddress),
containsPhysicalAddress = Regex.Match(m.Value, #"(?ix)Physical \s Address").Success,
content = m.Value
}).Where(x => x.containsIp && x.containsPhysicalAddress)
.Select(m => Regex.Match(m.content, #"(?ix) Physical \s address [^:]+ : \s* (?<Mac>[^\s]+)").Groups["Mac"].Value).FirstOrDefault();
return connection;
}

Really hate to dig up this old post but I feel the question deserves another answer specific to windows 8-10.
Using NetworkInformation from the Windows.Networking.Connectivity namespace, you can get the Id of the network adapter windows is using. Then you can get the interface MAC Address from the previously mentioned GetAllNetworkInterfaces().
This will not work in Windows Store Apps as NetworkInterface in System.Net.NetworkInformation does not expose GetAllNetworkInterfaces.
string GetMacAddress()
{
var connectionProfile = NetworkInformation.GetInternetConnectionProfile();
if (connectionProfile == null) return "";
var inUseId = connectionProfile.NetworkAdapter.NetworkAdapterId.ToString("B").ToUpperInvariant();
if(string.IsNullOrWhiteSpace(inUseId)) return "";
var mac = NetworkInterface.GetAllNetworkInterfaces()
.Where(n => inUseId == n.Id)
.Select(n => n.GetPhysicalAddress().GetAddressBytes().Select(b=>b.ToString("X2")))
.Select(macBytes => string.Join(" ", macBytes))
.FirstOrDefault();
return mac;
}

string mac = "";
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == OperationalStatus.Up && (!nic.Description.Contains("Virtual") && !nic.Description.Contains("Pseudo")))
{
if (nic.GetPhysicalAddress().ToString() != "")
{
mac = nic.GetPhysicalAddress().ToString();
}
}
}
MessageBox.Show(mac);

Changed blak3r his code a bit. In case you have two adapters with the same speed. Sort by MAC, so you always get the same value.
public string GetMacAddress()
{
const int MIN_MAC_ADDR_LENGTH = 12;
string macAddress = string.Empty;
Dictionary<string, long> macPlusSpeed = new Dictionary<string, long>();
try
{
foreach(NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
System.Diagnostics.Debug.WriteLine("Found MAC Address: " + nic.GetPhysicalAddress() + " Type: " + nic.NetworkInterfaceType);
string tempMac = nic.GetPhysicalAddress().ToString();
if(!string.IsNullOrEmpty(tempMac) && tempMac.Length >= MIN_MAC_ADDR_LENGTH)
macPlusSpeed.Add(tempMac, nic.Speed);
}
macAddress = macPlusSpeed.OrderByDescending(row => row.Value).ThenBy(row => row.Key).FirstOrDefault().Key;
}
catch{}
System.Diagnostics.Debug.WriteLine("Fastest MAC address: " + macAddress);
return macAddress;
}

foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == OperationalStatus.Up)
{
PhysicalAddress Mac = nic.GetPhysicalAddress();
}
}

ipconfig.exe is implemented using various DLLs including iphlpapi.dll ... Googling for iphlpapi reveals a corresponding Win32 API documented in MSDN.

Try this:
/// <summary>
/// returns the first MAC address from where is executed
/// </summary>
/// <param name="flagUpOnly">if sets returns only the nic on Up status</param>
/// <returns></returns>
public static string[] getOperationalMacAddresses(Boolean flagUpOnly)
{
string[] macAddresses = new string[NetworkInterface.GetAllNetworkInterfaces().Count()];
int i = 0;
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == OperationalStatus.Up || !flagUpOnly)
{
macAddresses[i] += ByteToHex(nic.GetPhysicalAddress().GetAddressBytes());
//break;
i++;
}
}
return macAddresses;
}

Related

How to retrieve the onboard ethernet MAC address of a computer?

I am trying to retrieve the MAC address for the onboard ethernet adapter from a computer, in order to generate a unique identifier for the device. Below is the approach I am using.
NetworkInterface[] ifConfig = NetworkInterface.GetAllNetworkInterfaces();
int maxHash = int.MinValue;
Guid D = Guid.Empty;
foreach (NetworkInterface net in ifConfig)
{
if (net.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
if (maxHash < net.GetPhysicalAddress().ToString().GetHashCode())
{
maxHash = net.GetPhysicalAddress().ToString().GetHashCode();
ID = new Guid(String.Concat("00000000-0000-0000-0000-", net.GetPhysicalAddress().ToString()));
}
}
}
However, the Bluetooth adapter, VM adapter and several other network adapters are also of the NetworkInterfaceType.Ethernet type. How can I specifically get the onboard ethernet connection's MAC address?
Doing a contains to omit those wouldn't be possible. Any help would be much appreciated.
I recently wrote a Powershell Script to generate a permanent system-format-immutable unique ID for a Windows PC for inventory purposes (QR encode the ID, print it on a sticker...).
It concatenates the PC manufacturer UUID field with the permanent MAC address of every PCI-connected network adapter (sorted alphabetically by MAC). The PCI requirement automatically dismisses removable or virtual NICs. The real script MD5-hashes the resulting string in order to obtain a more homogeneous identifier (constant length and 0-9A-F set of symbols), but I will omit this here for the sake of simplicity
I could’ve settled for the PC manufacturer UUID and call it a day, but I didn’t feel comfortable with an ID that relies on:
Each PC manufacturer in the world making the effort of filling in the UUID BIOS field.
Every PC manufacturer making the effort of keeping track of already used UUIDs
Basically, I tried to adhere to the intuitive idea of putting in the mixer as many non-removable components with permanent and “unique” (dream on) identifier as possible.
This ID generation technique is not fail proof: if a new PCI network adapter is added to the system, the ID will change. But with the popularization of integrated NICs I believe this is no longer something to worry about, if it ever was.
This solution is not directly applicable for C#, but I believe it can be easily adapted since Powershell shares almost the same .net object-class ecosystem.
#Variable names in spanish, but if I try to translate them in a hurry
#I will most certainly end up with a non-working script
$elpc=(Get-WmiObject -Class Win32_ComputerSystemProduct)
$id=$elpc.UUID #This is the UUID the manufacturer wrote somewhere in the BIOS
#Get network devices
#"Net" for network devices, "PCI*" because PCI connected devices begin that way
$dispositivosdered=#(Get-PnpDevice | Where-Object {($_.Class -eq "Net") -and ($_.InstanceId -like "PCI*")})
#Get network adapters
#Use "PermanentAddress" property. "MacAddress" property can be spoofed easily
$tarjetasdered=#(Get-Netadapter | Sort-Object PermanentAddress)
#Double loop to rule out any network adapters which are not PCI
#Comparison is made using long name, ie "Realtek PCIe GBE Family Controller #2"
#Is the only valid field I found to (inner) join the device and adapter worlds
for($j=0; $j -lt $tarjetasdered.length; $j++) {
for ($i=0; $i -lt $dispositivosdered.length; $i++) {
if($dispositivosdered[$i].FriendlyName -eq $tarjetasdered[$j].InterfaceDescription) {
if(-not [string]::IsNullOrEmpty($tarjetasdered[$j].PermanentAddress)) {
$id= $id + $tarjetasdered[$j].PermanentAddress.Replace("-", "");
}
}
}
}
As an option (not the best, but still =) ) - You can try to use
metric. In most cases the metric of the network to a physical network
card priority
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Management;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
ManagementObjectSearcher query = new
ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'TRUE'");
ManagementObjectCollection queryCollection = query.Get();
foreach (ManagementObject mo in queryCollection)
{
if (!(mo["Description"].ToString().Contains("VM")))
{
if (!(mo["Description"].ToString().Contains("Virtual")))
{
if (!(mo["Description"].ToString().Contains("Hyper")))
{
string[] addresses = (string[])mo["IPAddress"];
string IPConnectionMetric = Convert.ToString(mo["IPConnectionMetric"]).Trim();
foreach (string ipaddress in addresses)
{
listBox1.Items.Add(ipaddress + ";" + IPConnectionMetric);
}
}
private void button2_Click(object sender, EventArgs e)
{
if (listBox1.Items.Count > 1)
{
int maximum = int.MinValue;
int minimum = int.MaxValue;
for (int i = 0; i < listBox1.Items.Count; i++)
{
int output = Convert.ToInt32(listBox1.Items[i].ToString().Split(';')[1]);
if ((int)output > maximum)
maximum = (int)output;
}
for (int i = 0; i < listBox1.Items.Count; i++)
{
int output = Convert.ToInt32(listBox1.Items[i].ToString().Split(';')[1]);
if ((int)output < maximum)
minimum = (int)output;
if (listBox1.Items[i].ToString().Contains(minimum.ToString()))
{
var minmetric = listBox1.Items[i].ToString();
NetworkInterface[] ifConfig = NetworkInterface.GetAllNetworkInterfaces();
int maxHash = int.MinValue;
Guid D = Guid.Empty;
foreach (NetworkInterface net in ifConfig)
{
if (net.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
if (maxHash < net.GetPhysicalAddress().ToString().GetHashCode())
{
maxHash = net.GetPhysicalAddress().ToString().GetHashCode();
foreach (UnicastIPAddressInformation ip in net.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
if (ip.Address.ToString().Contains(minmetric.ToString().Split(';')[0]))
{
var ID = new Guid(String.Concat("00000000-0000-0000-0000-", net.GetPhysicalAddress().ToString()));
}
}
else
{
NetworkInterface[] ifConfig = NetworkInterface.GetAllNetworkInterfaces();
int maxHash = int.MinValue;
Guid D = Guid.Empty;
foreach (NetworkInterface net in ifConfig)
{
if (net.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
if (maxHash < net.GetPhysicalAddress().ToString().GetHashCode())
{
maxHash = net.GetPhysicalAddress().ToString().GetHashCode();
var ID = new Guid(String.Concat("00000000-0000-0000-0000-", net.GetPhysicalAddress().ToString()));
}
}
}
using system.Management;
private string GetMACAddress()
{
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
string MACAddress = String.Empty;
foreach (ManagementObject mo in moc)
{
if (MACAddress == String.Empty) // only return MAC Address from first card
{
if ((bool)mo["IPEnabled"] == true) MACAddress = mo["MacAddress"].ToString();
}
mo.Dispose();
}
MACAddress = MACAddress.Replace(":", "");
return MACAddress;
}

How to Change Public IP Address in C#

I am creating a C# winform application, in which I want to change the Public IP Address, NOT the IPv4 Address like (Hotspot-Shield, ZenMate, OpenVPN, and others do).
I have checked the following links but didn't find enough help, so I am posting this question:
How can you change Network settings (IP Address, DNS, WINS, Host Name) with code in C#
Changing IP address in C#
I write the same code as in the answer of 1st link and also used the libraries but when I check my IP address through google.com it remains the same. I don't know the socket programming.
Here is my code:
namespace WindowsFormsApplication1
{
class ChangeIP
{
public void SetIP(string ipAddress, string subnetMask, string gateway)
{
using (var networkConfigMng = new ManagementClass("Win32_NetworkAdapterConfiguration"))
{
using (var networkConfigs = networkConfigMng.GetInstances())
{
foreach (var managementObject in networkConfigs.Cast<ManagementObject>().Where(managementObject => (bool)managementObject["IPEnabled"]))
{
using (var newIP = managementObject.GetMethodParameters("EnableStatic"))
{
// Set new IP address and subnet if needed
if ((!String.IsNullOrEmpty(ipAddress)) || (!String.IsNullOrEmpty(subnetMask)))
{
if (!String.IsNullOrEmpty(ipAddress))
{
newIP["IPAddress"] = new[] { ipAddress };
}
if (!String.IsNullOrEmpty(subnetMask))
{
newIP["SubnetMask"] = new[] { subnetMask };
}
managementObject.InvokeMethod("EnableStatic", newIP, null);
}
// Set mew gateway if needed
if (!String.IsNullOrEmpty(gateway))
{
using (var newGateway = managementObject.GetMethodParameters("SetGateways"))
{
newGateway["DefaultIPGateway"] = new[] { gateway };
newGateway["GatewayCostMetric"] = new[] { 1 };
managementObject.InvokeMethod("SetGateways", newGateway, null);
}
}
}
}
}
}
}
/// <summary>
/// Set's the DNS Server of the local machine
/// </summary>
/// <param name="nic">NIC address</param>
/// <param name="dnsServers">Comma seperated list of DNS server addresses</param>
/// <remarks>Requires a reference to the System.Management namespace</remarks>
public void SetNameservers(string nic, string dnsServers)
{
using (var networkConfigMng = new ManagementClass("Win32_NetworkAdapterConfiguration"))
{
using (var networkConfigs = networkConfigMng.GetInstances())
{
foreach (var managementObject in networkConfigs.Cast<ManagementObject>().Where(objMO => (bool)objMO["IPEnabled"] && objMO["Caption"].Equals(nic)))
{
using (var newDNS = managementObject.GetMethodParameters("SetDNSServerSearchOrder"))
{
newDNS["DNSServerSearchOrder"] = dnsServers.Split(',');
managementObject.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
}
}
}
}
}
}
}
And Here is how I am calling those methods:
{
static string local_ip;
string public_ip;
public static string GetLocalIPAddress() //Method For Getting Local Machine IP
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
throw new Exception("Local IP Address Not Found!");
}
// Mehod End
local_ip = GetLocalIPAddress();
ChangeIP ip = new ChangeIP();
ip.SetIP(local_ip, null, null); // Calling Method
var getNIC = NetworkInterface.GetAllNetworkInterfaces();
NetworkInterface[] NI = NetworkInterface.GetAllNetworkInterfaces();
string nic = string.Empty;
string dnsServer = string.Empty;
foreach(var r in getNIC)
{
nic = r.Name;
}
foreach(NetworkInterface ninter in NI)
{
if(ninter.OperationalStatus == OperationalStatus.Up)
{
IPInterfaceProperties ipProperties = ninter.GetIPProperties();
IPAddressCollection dnsAddresses = ipProperties.DnsAddresses;
foreach(IPAddress dnsAdrs in dnsAddresses)
{
dnsServer = dnsAdrs.ToString();
}
}
}
ip.SetNameservers(nic, dnsServer); // Calling Method
public_ip = new WebClient().DownloadString("http://icanhazip.com");
}
How you've described your question is not how the internet (is supposed to) work(s).
Windows doesn't let you write raw IP packets, for this you need to use a TAP/TUN driver. But although you send out packets spoofing the source IP address, the internet between you and the destination won't return the route.
If you're operating behind a block of IP addresses, and only want to spoof another in that block, the return address will get back to your local router, but still won't necessary route back to you.
Unless you use TAP/TUN, there's no other way to steal someone else's Public IP address, excluding other network security vulnerability exploitations which are beyond the scope of this forum.
And even with TAP/TUN you're very limited in what you can achieve over spoofed IP packets in one direction. In fact, ISPs may filter out spoofed IP addresses.

Determine which network adapter has the highest priority in C#?

If we have multiple network interfaces with the same DNS suffix on a given machine, how do I programatically determine which network interface traffic will be routed over?
For example, I am connected to my companies network via ethernet in office, and connected to the companies network via VPN from inside the office. This sounds stupid, but with the way our networks are connected, if the internal link to our datacenter goes down - I VPN from inside the office to continue development.
Our software has logic to determine our "local ip address" and uses that for authentication logic elsewhere. I know from practice that all my traffic is routed over the VPN when connected - but am struggling with what the correct implementation in code is for robustly choosing the IP address of the adapter with the highest priority.
What I have right now is:
var unicastIpAddressInformation = NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up
&& nic.NetworkInterfaceType != NetworkInterfaceType.Loopback // ...ignore the loopback NIC as we don't want 127.0.0.1 (1 of 2)
&& nic.Name.IndexOf("loopback", StringComparison.OrdinalIgnoreCase) == -1 // ...ignore the loopback NIC as we don't want 127.0.0.1 (2 of 2)
&& nic.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) == -1 // ... ignore virtual NICs so that VMs don't conflict with IP resolution
)
.Select(n => n.GetIPProperties())
// All developer network connections should have the my-company-internal.com suffix
.Where(ipp => ipp.DnsSuffix.ToLowerInvariant().IndexOf("my-company-internal.com", StringComparison.OrdinalIgnoreCase) >= 0)
.Where(ipp => ipp.UnicastAddresses.Any(u => u.Address.AddressFamily == AddressFamily.InterNetwork))
// Is this order by correct?
.OrderByDescending(ipp => ipp.GetIPv4Properties().Index)
.SelectMany(ipp => ipp.UnicastAddresses.Where(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork))
.FirstOrDefault();
I know with the IPV4Properties.Index - it is only populated when IPv4 is enabled; I don't know if corresponds to priority or metric, and whether or not they are guaranteed to be distinct.
I had the same problem here a few weeks ago. I figured out that the NIC priority is persisted in Windows Registry, and there are a few PowerShell scripts that can give you the NIC order, but not the IP addresses. So, I've written the code below and it worked for me. You can use it to see additional info like dns suffix, gateway address and plus.
You just have to call RMSNetUtils.GetTopIpv4Ip(string.Empty)
public class RMSNetUtils
{
private static string _linkagePath = #"SYSTEM\CurrentControlSet\Services\Tcpip\Linkage";
private static string _interfacesPath = #"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\";
private static List<string> GetBindingsPriority()
{
using (var bindMasterKey = Registry.LocalMachine.OpenSubKey(_linkagePath))
{
var bind = (string[]) bindMasterKey.GetValue("Bind");
var deviceList = bind.Select(x => $#"{_interfacesPath}{x.Replace("\\Device\\", string.Empty)}")
.ToList();
var result = new List<string>();
foreach (var device in deviceList)
{
using (var bindKey = Registry.LocalMachine.OpenSubKey(device))
{
var fixIP = (string[])bindKey.GetValue("IPAddress");
if (fixIP != null)
{
result.Add( fixIP.FirstOrDefault());
continue;
}
var dhcpIp = bindKey.GetValue("DhcpIPAddress");
if (dhcpIp != null)
{
result.Add((string) dhcpIp);
}
}
}
return result;
}
}
private static List<NICInformation> GetFilteredBindings()
{
var bindings = GetBindingsPriority();
var nicsInfo = GetIpList(GetInterNetworkAdapters());
var result = new List<NICInformation>();
foreach (var bind in bindings)
{
var nicInfo = nicsInfo.FirstOrDefault(y => string.Compare(y.IPv4, bind) == 0);
if(nicInfo!= null)
result.Add(nicInfo);
}
return result;
}
private static IEnumerable<IPAddress> GetInterNetworkAdapters()
{
IPHostEntry local = Dns.GetHostEntry(string.Empty);
return (from ipa in local.AddressList
where ipa.AddressFamily == AddressFamily.InterNetwork
select ipa);
}
public static string GetFirstIpv4Ip()
{
return GetFirstIpv4Ip(String.Empty);
}
private static List<NICInformation> GetIpList(IEnumerable<IPAddress> ips)
{
var ipAddresses = ips.Select(x => x.ToString()).ToList();
var result = new List<NICInformation>();
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
if (ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
var ipStr = ip.Address.ToString();
if (ipAddresses.Contains(ipStr))
{
var nic = new NICInformation();
nic.IPv4 = ip.Address.ToString();
nic.Mask = ip.IPv4Mask.ToString();
nic.DnsSuffix = ni.GetIPProperties().DnsSuffix;
var gateway = ni.GetIPProperties().GatewayAddresses.FirstOrDefault();
if(gateway!=null)
nic.Gateway = gateway.Address.ToString();
result.Add(nic);
}
}
}
}
}
return result;
}
public static string GetTopIpv4Ip(string hostName)
{
if (!string.IsNullOrEmpty(hostName))
return GetFirstIpv4Ip(hostName);
var item = GetFilteredBindings().FirstOrDefault();
return item == null ? hostName : item.IPv4;
}
public static string GetFirstIpv4Ip(string hostName)
{
var ip = string.Empty;
try
{
IPHostEntry local = Dns.GetHostEntry(hostName);
var result = GetInterNetworkAdapters().FirstOrDefault();
return result != null ? result.ToString() : hostName;
}
catch (SocketException ex)
{
ip = hostName;
}
return ip;
}
}
public class NICInformation
{
public string DnsSuffix {get;set;}
public string IPv4 {get;set; }
public string Gateway {get;set;}
public string Mask {get;set;}
}

How to obtain Public IP of a device using C# with out using external API/Services

public static string GetPublicIp()
{
HttpContext context = HttpContext.Current;
string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (!string.IsNullOrEmpty(ipAddress))
{
string[] addresses = ipAddress.Split(',');
if (addresses.Length != 0)
{
return addresses[0];
}
}
return context.Request.ServerVariables["REMOTE_ADDR"];
}
I'm trying to get the client Public IP but the above code only returns the client Local IP. If different people are connecting to my organisation from the same organisations network, i want to get only their public IP address. I'm not intrested in their local IPs, is this possible.
Below is one solution i have so far seen but i'm NOT liking it.
public static string GetPublicIp()
{
string direction = "";
WebRequest request = WebRequest.Create("http://checkip.dyndns.org");
using (WebResponse response1 = request.GetResponse())
using (StreamReader stream1 = new StreamReader(response1.GetResponseStream()))
{
direction = stream1.ReadToEnd();
}
//Search for the ip in the html
int first1 = direction.IndexOf("Address: ") + 9;
int last1 = direction.LastIndexOf("</body>");
direction = direction.Substring(first1, last1 - first1);
return direction;
}
The above sample solution can get me the public IP but i don't want to be tied to an external service that i have no control over because if that service is down then iam screwed and the performance is terrible.
Does any one know how i can get the clients public IP with out calling external services?
This method gives you the local ip address. I've copied it from a WinRT-Solution, maybe the class names are a bit different in other .NET environments.
private static string GetLocalAddress()
{
var hostnames = NetworkInformation.GetHostNames();
foreach (var hn in hostnames)
{
//IanaInterfaceType == 71 => Wifi
//IanaInterfaceType == 6 => Ethernet (Emulator)
if (hn.IPInformation != null &&
(hn.IPInformation.NetworkAdapter.IanaInterfaceType == 71
|| hn.IPInformation.NetworkAdapter.IanaInterfaceType == 6))
{
return hn.DisplayName;
}
}
return IpAddress.Broadcast.Address;
}
EDIT: The following method prints out all local ip addresses.
private static void PrintLocalAddresses()
{
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in interfaces)
{
if (ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
{
var adapterProperties = ni.GetIPProperties();
foreach (var x in adapterProperties.UnicastAddresses)
{
if (x.Address.AddressFamily == AddressFamily.InterNetwork)
{
Console.WriteLine(x.Address);
}
}
}
}
}

How to get IPv4 and IPv6 address of local machine?

I am developing a windows application and I need to find the IPv4 and IPv6 address of local machine. OS can be XP or Windows 7.
I got a solution for getting MAC address like,
string GetMACAddress()
{
var macAddr =
(
from nic in NetworkInterface.GetAllNetworkInterfaces()
where nic.OperationalStatus == OperationalStatus.Up
select nic.GetPhysicalAddress().ToString()
).FirstOrDefault();
return macAddr.ToString();
}
This is working in all OS.
What is the correct way to get IPv4 and IPv6 address that work on XP and WINDOWS 7?
string strHostName = System.Net.Dns.GetHostName();;
IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(strHostName);
IPAddress[] addr = ipEntry.AddressList;
Console.WriteLine(addr[addr.Length-1].ToString());
if (addr[0].AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
Console.WriteLine(addr[0].ToString()); //ipv6
}
To get all IP4 and IP6 address, here is my preferred solution. Note that it also filters the loopback IP addresses like 127.0.0.1 or ::1
public static IEnumerable<IPAddress> GetIpAddress()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
return (from ip in host.AddressList where !IPAddress.IsLoopback(ip) select ip).ToList();
}
Here's my method for getting all the IPv4 addresses only.
/// <summary>
/// Gets/Sets the IPAddress(s) of the computer which the client is running on.
/// If this isn't set then all IPAddresses which could be enumerated will be sent as
/// a comma separated list.
/// </summary>
public string IPAddress
{
set
{
_IPAddress = value;
}
get
{
string retVal = _IPAddress;
// If IPAddress isn't explicitly set then we enumerate all IP's on this machine.
if (_IPAddress == null)
{
// TODO: Only return ipaddresses that are for Ethernet Adapters
String strHostName = Dns.GetHostName();
IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
IPAddress[] addr = ipEntry.AddressList;
List<string> validAddresses = new List<string>();
// Loops through the addresses and creates a list of valid ones.
for (int i = 0; i < addr.Length; i++)
{
string currAddr = addr[i].ToString();
if( IsValidIP( currAddr ) ) {
validAddresses.Add( currAddr );
}
}
for(int i=0; i<validAddresses.Count; i++)
{
retVal += validAddresses[i];
if (i < validAddresses.Count - 1)
{
retVal += ",";
}
}
if (String.IsNullOrEmpty(retVal))
{
retVal = String.Empty;
}
}
return retVal;
}
}

Categories