繁体   English   中英

如何在C#中获取IP机器的NetBIOS名称?

[英]How do I get the NetBIOS name of a machine from IP in C#?

给定机器的 IP 地址,我如何在 C# 中以编程方式获取其 NetBIOS 名称? 我知道我可以通过“nbtstat -A”从命令行获取它,但我正在寻找更好的解决方案。

检查使用Socket类通过UDP请求设备的NetBios名称 (向下滚动)。

编辑

社区已根据原始页面上的404编辑了URL,并将链接更改为从web.archive.org拉取

我使用的代码基于我曾经在微软找到的一个例子。 当它在端口 137 获得 UDP 请求的结果时,它会从答案中删除名称。 它不检查名称是否为有效的 NetBIOS 名称。 可以添加它以使其更安全。

public class NetBIOSHelper
{
    /// <summary>
    /// Get the NetBIOS machine name and domain / workgroup name by ip address using UPD datagram at port 137. Based on code I found at microsoft 
    /// </summary>
    /// <returns>True if getting an answer on port 137 with a result</returns>
    public static bool GetRemoteNetBiosName(IPAddress targetAddress, out string nbName, out string nbDomainOrWorkgroupName, int receiveTimeOut = 5000, int retries = 1)
    {
        // The following byte stream contains the necessary message
        // to request a NetBios name from a machine
        byte[] nameRequest = new byte[]{
        0x80, 0x94, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21,
        0x00, 0x01 };

        do
        {
            byte[] receiveBuffer = new byte[1024];
            Socket requestSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            requestSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeOut);

            nbName = null;
            nbDomainOrWorkgroupName = null;

            EndPoint remoteEndpoint = new IPEndPoint(targetAddress, 137);
            IPEndPoint originEndpoint = new IPEndPoint(IPAddress.Any, 0);
            requestSocket.Bind(originEndpoint);
            requestSocket.SendTo(nameRequest, remoteEndpoint);
            try
            {
                int receivedByteCount = requestSocket.ReceiveFrom(receiveBuffer, ref remoteEndpoint);

                // Is the answer long enough?
                if (receivedByteCount >= 90)
                {
                    Encoding enc = new ASCIIEncoding();
                    nbName = enc.GetString(receiveBuffer, 57, 15).Trim();
                    nbDomainOrWorkgroupName = enc.GetString(receiveBuffer, 75, 15).Trim();

                    // the names may be checked if they are really valid NetBIOS names, but I don't care ....

                    return true;
                    //<----------
                }
            }
            catch (SocketException)
            {
                // We get this Exception when the target is not reachable
            }

            retries--;

        } while (retries >= 0);

        return false;
        //< ----------
    }
}

您可以使用类型为AF_NETBIOS winapi gethostbyaddr

作为旁白; 在尝试将接收到的 MAC 地址 map 发送到组织名称 (/vendor) 方面,至少作为指南,这可能会有所帮助:

            IDictionary<string, string> ouiToOrgName = null;

            using (var httpClnt = new System.Net.Http.HttpClient())
            {
                var ouiTxt =
                    await httpClnt.GetStringAsync(@"https://standards-oui.ieee.org/oui/oui.txt");

                var ouiTxtList =
                    ouiTxt
                        .Split('\n')
                        .Where(x => x.Contains(@"(hex)"))
                        .ToList();

                ouiToOrgName =
                    new SortedDictionary<string, string>();

                foreach (var line in ouiTxtList)
                {
                    var match = OuiTxtOuiOrgNameRe.Match(line);

                    if (match.Success &&
                        // Ignore duplicates
                        ! ouiToOrgName.ContainsKey(match.Groups[1].Value))
                    {
                        ouiToOrgName.Add(
                            match.Groups[1].Value,
                            match.Groups[2].Value);
                    }
                }
            }

            return ouiToOrgName;

...

        private static readonly Regex OuiTxtOuiOrgNameRe =
            new Regex(
                @"((?:[0-9A-F]{2}-){2}[0-9A-F]{2})(?: *)(?:\(hex\))(?:\t*)(.*)",
                // RegexOptions.Multiline |
                RegexOptions.Compiled);

我稍微完成了上面介绍的class(NetBIOSHelper)。 它错误地给出了 Windows 7 的工作组,但正确地给出了 Windows 10。因为 win7 的 nbtstat 首先给出所有名称,然后给出所有组,win10 名称,组,名称,组。 好吧,至少在 my.network 中。 还增加了另一个 boolean 返回参数,它表示给定的计算机是否是该组的主浏览器(MasterBrowser)。 那么,function 现在只返回 object[], [string computername,string workgroup,bool isMasterBrowser]

public class NetBIOSHelper{

public static object[] GetRemoteNetBiosName(IPAddress targetAddress, int receiveTimeOut = 5000, int retries = 1){
    byte[] nameRequest = new byte[]{
    0x80, 0x94, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21,
    0x00, 0x01 };

    string workgroup = "";
    string compname = "";
    bool isMasterBrowser = false;
    do
    {
        byte[] receiveBuffer = new byte[1024];
        Socket requestSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        requestSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeOut);


        EndPoint remoteEndpoint = new IPEndPoint(targetAddress, 137);
        IPEndPoint originEndpoint = new IPEndPoint(IPAddress.Any, 0);
        requestSocket.Bind(originEndpoint);
        requestSocket.SendTo(nameRequest, remoteEndpoint);
        try
        {
            int receivedByteCount = requestSocket.ReceiveFrom(receiveBuffer, ref remoteEndpoint);
            if (receivedByteCount >= 90)
            {
                Encoding enc = new ASCIIEncoding();

                 for(int i = 0; i < 5; i++){                            
                        var name = enc.GetString(receiveBuffer, 57+i*18, 15).Trim();
                        var b1 = receiveBuffer[57 + i * 18 + 15];
                        var b2 = receiveBuffer[57 + i * 18 + 16];
                        if ((b2 == 0x84 || b2 == 0x44) && b1 == 0x00)
                            workgroup = name;
                        if ((b2 == 0x04 || b2 == 0xC4) && b1 == 0x00)
                            compname = name;
                        if (b2 == 4 && b1 == 0x1D)
                            isMasterBrowser = true;
                    }

                return new object[]{
                        compname,
                        workgroup,
                        isMasterBrowser
                    };
            }
        }
        catch (SocketException e)
        {

        }

        retries--;

    } while (retries > 0);

    return null;
}
}

PS 还将循环条件更改为 while (retries > 0) 因为参数 1 它被调用了 2 次

PPS 至于第 16 个字节(变量 b1),我找到了它是什么,这是它的值:

  • 00 标准工作站服务
  • 03 信使服务(WinPopup)
  • 06 RAS 服务器服务
  • 1B 域主浏览器服务(与主域控制器关联)
  • 一维主浏览器名称
  • 1F NetDDE 服务
  • 20 文件服务器(包括打印机服务器)
  • 21 RAS 客户服务
  • BE网络监控代理
  • BF 网络监视器实用程序

对于组资源:

  • 00 标准工作站组
  • 1C登录服务器
  • 一维主浏览器名称
  • 1E Normal 组名(用于浏览器选举)
  • 20 Inte.net 组名(行政)
  • 01- MSBROWSE (提醒其他主浏览器)

您可以在此处阅读更多关于包含第 17 个字节(变量 b2)和第 18 个字节的内容,您已经需要将它们分成几位。 但在我的示例中,我设置了出现在 my.network 中的值。 通常,您可以在RFC 1001RFC 1002中阅读有关 NetBIOS 的更多信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM