На C# .Чистая получать MAC-адрес локальной сетевой адаптер, что делает подключение к определенному хосту


ну, как сказал в названии: мы должны получить MAC-адрес сетевой адаптер, который обеспечивает подключение к этому узлу. Мы используем MAC-адрес во время процесса входа в систему с использованием MSSQL и базы предприятия.

технологии: C#.NET 4.0, 4.1 эф

private string _max_address;
public string ConnectionString { get; };

public string MacAddress {
    get {
        if (this._mac_address == null) {
            SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder(this.ConnectionString);

            IPAddress[] addres = Dns.GetHostAddresses(csb.DataSource.Split('\\')[0]);
            //find nic interface address from routing table

            Process p = new Process();
            // Redirect the output stream of the child process.
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.StartInfo.CreateNoWindow = false;
            p.StartInfo.FileName = "route";
            p.StartInfo.Arguments = "PRINT";
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            p.Close();
            p.Dispose();


            string[] lines = output.Split(new string[]{"\r\n"}, StringSplitOptions.RemoveEmptyEntries);

            List<Route> routes = new List<Route>();
            bool found = false;
            foreach (string line in lines) {
                if (line == "Active Routes:") {
                    if (found) //if routes have already been found exit loop, meaning this is IPv6 routes, should never reach this point
                        break;
                    found = true;
                    continue; //next line
                }

                if (found) {
                    if (line[0] == 'N')  //if the line is headers skip it
                        continue;
                    else if (line[0] == '=')  //if the routes have ended exit loop
                        break;
                    routes.Add(new Route(line)); //read route, custom class
                }
            }
            routes.Sort(); //sort routes by Mask, then by Address
            string nic_addr = "";

            foreach (IPAddress addr in addres) {
                if (addr.AddressFamily == AddressFamily.InterNetwork) { //if IPv4
                    for (int i = routes.Count - 1; i >= 0; i--) { //start from the largest Mask
                        if(routes[i].IncludesHost(addr)) { //whether the ip fits in the subnet
                            nic_addr = routes[i].ReadableInterface;
                            break; //if so, save interface name, exit loop
                        }
                    }
                    break;
                }
            }

            //Get NIC of found Interface by IP
            foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
                if (nic.OperationalStatus == OperationalStatus.Up) {
                    IPInterfaceProperties properties = nic.GetIPProperties();
                    foreach (UnicastIPAddressInformation addr_info in properties.UnicastAddresses) {
                        if (addr_info.Address.AddressFamily == AddressFamily.InterNetwork && addr_info.Address.ToString()==nic_addr) {
                            this._mac_address = nic.GetPhysicalAddress().ToString();
                            break;  //if address matches that of the routing table interface address then save MAC and exit loop
                        }
                    }
                    if (this._mac_address != null)
                        break; //if mac address is found exit loop;
                }
            }
        }
        return this._mac_address;
    }
}

public class Route : IComparable
{
    private uint _address;
    private uint _mask;
    private uint _interface;
    private int _metric;

    public uint Address { get { return this._address; } }
    public uint Mask { get { return this._mask; } }
    public uint Interface { get { return this._interface; } }

    public string ReadableAddress { get { return Route.IPLongToString(this._address); } }
    public string ReadableMask { get { return Route.IPLongToString(this._mask); } }
    public string ReadableInterface { get { return Route.IPLongToString(this._interface); } }

    public Route(string[] route)
    {
        this._address=IPStringToLong(route[0]);
        this._mask=IPStringToLong(route[1]);
        this._interface=IPStringToLong(route[3]);
        this._metric=UInt16.Parse(route[4]);
    }

    public Route(string line)
        : this(line.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries))
    {
    }

    public static uint IPStringToLong(string str)
    {
        string[] values = str.Split(new char[]{'.'});
        uint multiplier = 1;
        uint value = 0;
        for(int i=3;i>=0;i--) {
            value+=UInt32.Parse(values[i])*multiplier;
            multiplier*=256;
        }
        return value;
    }

    public static string IPLongToString(uint addr)
    {
        byte[] bytes = BitConverter.GetBytes(addr);
        string[] bs = new string[]{"","","",""};

        for(int i=0;i<4;i++) {
             bs[i] = bytes[3-i].ToString();
        }
        return String.Join(".",bs);
    }

    public bool IncludesHost(IPAddress addr)
    {
        if (addr.AddressFamily == AddressFamily.InterNetwork)
            return this.IncludesHost(Route.IPStringToLong(addr.ToString()));
        else
            return false;
    }

    public bool IncludesHost(string addr)
    {
        return this.IncludesHost(Route.IPStringToLong(addr));
    }

    public bool IncludesHost(long addr)
    {
        return (this._mask&this._address) == (this._mask&addr);
    }

    public int CompareTo(object _y)
    {
        Route y = (Route)_y;
        if (y == null) 
            return 1;
        else
        {
            int retval = this.Mask.CompareTo(y.Mask);
            if (retval != 0) 
                return retval;
            else 
                return this.CompareToByAddress(y);
        }
    }
}

Редактировать:

до сих пор, это ужас мне не нравится решение, которое я придумал.

  1. получить имя хоста из свойства connectionString
  2. получить IP адрес от хоста
  3. выполнить "путь принт"
  4. поставить вывод в строку arrray
  5. петля через выход линии
  6. найти "активные маршруты" линия
  7. пропустить заголовок
  8. маршрут загрузить в пользовательский класс маршрут
  9. линия выход из цикла
  10. в цикле нашли маршрутов
  11. найти соответствия хоста IP, маска сети, маска
  12. сохранить его IP-интерфейс
  13. петля через NIC
  14. проверьте IPv4, если так проверить IP-интерфейс
  15. Мак, найденных ник

здесь нет более элегантный способ выполнить шаги с 1 по 14, это так много кода, просто чтобы получить MAC-адрес конкретного сетевого адаптера\

Или, по крайней мере, лучшего способа accomlish шаги с 3 по 10

Редактировать: Я пропустил объявление CompareToByAddress()

public int CompareToByAddress( Route y)
{
    if (y == null)
    {
        return 1;
    }
    else
    {
        int retval = this.Address.CompareTo(y.Address);
        if (retval != 0)
        {  
            return retval;
        }
        else
        {
            //should never reach this point meaning there's duplicate entry in the routing table
            return 0;
        }
    }
}

хотя, приведенным ниже рекомендациям Не используйте методы Сравнениедля;



5222
4
c#
задан 31 октября 2011 в 01:10 Источник Поделиться
Комментарии
2 ответа

Чтобы расширить ответ Strilanc, можно очистить немного дальше с следующие:

var address = addres.First(e => e.AddressFamily.Equals(AddressFamily.InterNetwork));

// Retrieve routing table
string output = string.Empty;
using (Process p = new Process()
{
StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
RedirectStandardOutput = true,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = false,
FileName = "route",
Arguments = "PRINT"
}
})
{
p.Start();
output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
p.Close();
}

// Find NIC interface from table
var nicAddr = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.SkipWhile(e => !e.Equals("Active Routes:"))
.Skip(1)
.TakeWhile(e => !e.Equals("Active Routes:"))
.TakeWhile(e => !e.StartsWith("="))
.Where(e => !e.StartsWith("N"))
.Select(e => new Route(e))
.OrderByDescending(e => e.Mask)
.ThenByDescending(e => e.Address)
.First(e => e.IncludesHost(address))
.ReadableInterface;

// Get MAC address of associated IP address
var macAddress = NetworkInterface.GetAllNetworkInterfaces()
.Where(e => e.OperationalStatus.Equals(OperationalStatus.Up))
.Where(e => e.GetIPProperties().UnicastAddresses
.Where(a => a.Address.AddressFamily.Equals(AddressFamily.InterNetwork) &&
a.Address.ToString().Equals(nicAddr)).FirstOrDefault() != null)
.Select(a => a.GetPhysicalAddress()).FirstOrDefault();

2
ответ дан 2 ноября 2011 в 07:11 Источник Поделиться

Я не знаю об этом непосредственно, но код может быть очищен с помощью LINQ, как начать.

var addr = addres.First(e => e.AddressFamily == AddressFamily.InterNetwork);
var nic_addr = output.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
.SkipWhile(e => e != "Active Routes:")
.Skip(1)
.TakeWhile(e => e != "Active Routes:") //if routes have already been found exit loop, meaning this is IPv6 routes, should never hit this case
.TakeWhile(e => e != "=") //until the routes have ended
.Where(e => !e.StartsWith("N")) //skip header lines
.Select(e => new Route(e))
.OrderByDescending(e => e.Mask)
.ThenByDescending(e => e.Address)
.First(e => e.IncludesHost(addr))
.ReadableInterface;

//Choose NIC matching the IP address
var result = NetworkInterface.GetAllNetworkInterfaces()
.Where(e => e.OperationalStatus == OperationalStatus.Up)
.SelectMany(e => e.GetIPProperties().UnicastAddresses)
.Where(e => e.Address.AddressFamily == AddressFamily.InterNetwork)
.Where(e => e.Address.ToString() == nic_addr)
.First();

0
ответ дан 2 ноября 2011 в 02:11 Источник Поделиться