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

发布于 2024-08-20 00:04:08 字数 90 浏览 5 评论 0原文

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

Given the IP address of a machine how do I get its NetBIOS name programmatically in C#? I know I can get it from the command line through "nbtstat -A ', but I'm looking for a better solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜宝宝 2024-08-27 00:04:08

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

编辑

社区已编辑了由于原始页面出现 404 错误而导致的 URL,并将链接更改为从 web.archive.org 提取

Check Using the Socket class to request the NetBios name of a device over UDP (scroll down).

EDIT

Community has edited the URL due to 404 on original page, and changed link to pull from web.archive.org

缘字诀 2024-08-27 00:04:08

我使用的代码是基于我在微软发现的一个例子。当它在端口 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;
        //< ----------
    }
}

I use this code which is based on an example I found once at microsoft. When it gets a result to a UDP request at port 137 it cuts of the names from the answer. It does not check if the names are valid NetBIOS names. This may be added to make it safer.

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;
        //< ----------
    }
}
许久 2024-08-27 00:04:08

您可以使用 winapi gethostbyaddr 类型 AF_NETBIOS

You could use winapi gethostbyaddr with type AF_NETBIOS.

聽兲甴掵 2024-08-27 00:04:08

顺便说一句;就尝试将收到的 MAC 地址映射到组织名称 (/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);

As an aside; in terms of attempting to map the received MAC Address to an Organisation Name (/vendor), at least as a guideline this might help :

            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);

终弃我 2024-08-27 00:04:08

我稍微完成了上面介绍的课程(NetBIOSHelper)。
它错误地为 Windows 7 提供了工作组,但为 Windows 10 提供了正确的工作组。
因为win7的nbtstat首先给出所有名称,然后给出所有组,而win10名称,组,名称,组。好吧,至少在我的网络中是这样。
还添加了另一个布尔返回参数,
它指示给定计算机是否是该组的主浏览器(MasterBrowser)。
好吧,函数现在只是返回 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 < receiveBuffer[56]; i++){                            
                        var name = enc.GetString(receiveBuffer, 57+i*18, 15).Trim();
                        byte b1 = receiveBuffer[57 + i * 18 + 15];
                        byte b2 = receiveBuffer[57 + i * 18 + 16];
                        if ((b2 & (1 << 7)) != 0 && (b2 & (1 << 2)) != 0 && b1 == 0x00)
                            workgroup = name;
                        if ((b2 & (1 << 7)) == 0 && (b2 & (1 << 2)) != 0 && b1 == 0x00)
                            compname = name;
                        if ((b2 & (1 << 2)) != 0 && 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 次

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

  • 00 Standard Workstation Service
  • 03 Messenger Service (WinPopup)
  • 06 RAS Server Service
  • 1B Domain Master浏览器服务(与主域关联
    控制器)
  • 1D 主浏览器名称
  • 1F NetDDE 服务
  • 20 文件服务器(包括打印机服务器)
  • 21 RAS 客户端服务
  • BE 网络监视器代理
  • BF 组资源网络监视器实用程序

  • 00 标准工作站组
  • 1C 登录服务器
  • 1D 主浏览器名称
  • 1E 正常组名称(用于浏览器选举)
  • 20 Internet 组名称(管理)
  • 01-MSBROWSE(有关其他主浏览器的警报)

您可以阅读有关包含第 17 个字节(变量 b2)和第 18 个字节的内容的更多信息 此处,您已经需要将它们分成几位。
一般来说,您可以在 RFC 1001RFC 1002这个

I slightly finished the class presented above (NetBIOSHelper).
It incorrectly gives Workgroup for Windows 7, but correctly for Windows 10.
Because nbtstat for win7 first gives all names and then all groups, and win10 name, group, name, group. Well, at least in my network.
Also added another boolean return parameter,
it indicates whether the given computer is the master browser of this group (MasterBrowser).
Well, the function now simply returns 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 < receiveBuffer[56]; i++){                            
                        var name = enc.GetString(receiveBuffer, 57+i*18, 15).Trim();
                        byte b1 = receiveBuffer[57 + i * 18 + 15];
                        byte b2 = receiveBuffer[57 + i * 18 + 16];
                        if ((b2 & (1 << 7)) != 0 && (b2 & (1 << 2)) != 0 && b1 == 0x00)
                            workgroup = name;
                        if ((b2 & (1 << 7)) == 0 && (b2 & (1 << 2)) != 0 && b1 == 0x00)
                            compname = name;
                        if ((b2 & (1 << 2)) != 0 && b1 == 0x1D)
                            isMasterBrowser = true;
                    }

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

        }

        retries--;

    } while (retries > 0);

    return null;
}
}

P.S. Also changed the loop condition to while (retries > 0)
Because with parameter 1 it is called 2 times

P.P.S. As for the 16th byte (variable b1), I found what it is, here are its values:

  • 00 Standard Workstation Service
  • 03 Messenger Service (WinPopup)
  • 06 RAS Server Service
  • 1B Domain Master Browser Service (associated with primary domain
    controller)
  • 1D Master Browser name
  • 1F NetDDE Service
  • 20 Fileserver (including printer server)
  • 21 RAS Client Service
  • BE Network Monitor Agent
  • BF Network Monitor Utility

for group resources:

  • 00 Standard Workstation group
  • 1C Logon Server
  • 1D Master Browser name
  • 1E Normal Group name (used in browser elections)
  • 20 Internet Group name (administrative)
  • 01-MSBROWSE (alert about others Master Browser)

You can read more about what contains the 17th byte (variable b2) and the 18th byte here, there you already need to divide them into bits.
In general, you can read more about NetBIOS in RFC 1001 and RFC 1002 and this

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文